diff --git a/NotificationService/Serialization.m b/NotificationService/Serialization.m index 00a0621e3e..f7eea7807e 100644 --- a/NotificationService/Serialization.m +++ b/NotificationService/Serialization.m @@ -3,7 +3,7 @@ @implementation Serialization - (NSUInteger)currentLayer { - return 109; + return 110; } - (id _Nullable)parseMessage:(NSData * _Nullable)data { diff --git a/Telegram-iOS/Resources/Compass.tgs b/Telegram-iOS/Resources/Compass.tgs new file mode 100644 index 0000000000..d9ec83eb77 Binary files /dev/null and b/Telegram-iOS/Resources/Compass.tgs differ diff --git a/Telegram-iOS/Resources/Dice_1.tgs b/Telegram-iOS/Resources/Dice_1.tgs new file mode 100644 index 0000000000..e078e6b6de Binary files /dev/null and b/Telegram-iOS/Resources/Dice_1.tgs differ diff --git a/Telegram-iOS/Resources/Dice_2.tgs b/Telegram-iOS/Resources/Dice_2.tgs new file mode 100644 index 0000000000..c350c4d88c Binary files /dev/null and b/Telegram-iOS/Resources/Dice_2.tgs differ diff --git a/Telegram-iOS/Resources/Dice_3.tgs b/Telegram-iOS/Resources/Dice_3.tgs new file mode 100644 index 0000000000..388043434d Binary files /dev/null and b/Telegram-iOS/Resources/Dice_3.tgs differ diff --git a/Telegram-iOS/Resources/Dice_4.tgs b/Telegram-iOS/Resources/Dice_4.tgs new file mode 100644 index 0000000000..0cc05f7cea Binary files /dev/null and b/Telegram-iOS/Resources/Dice_4.tgs differ diff --git a/Telegram-iOS/Resources/Dice_5.tgs b/Telegram-iOS/Resources/Dice_5.tgs new file mode 100644 index 0000000000..2005eef2f4 Binary files /dev/null and b/Telegram-iOS/Resources/Dice_5.tgs differ diff --git a/Telegram-iOS/Resources/Dice_6.tgs b/Telegram-iOS/Resources/Dice_6.tgs new file mode 100644 index 0000000000..6c298dde36 Binary files /dev/null and b/Telegram-iOS/Resources/Dice_6.tgs differ diff --git a/Telegram-iOS/en.lproj/Localizable.strings b/Telegram-iOS/en.lproj/Localizable.strings index c2aade54e4..67b8058d9d 100644 --- a/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram-iOS/en.lproj/Localizable.strings @@ -5284,3 +5284,22 @@ Any member of this group will be able to see messages in the channel."; "Map.PlacesInThisArea" = "Places In This Area"; "Conversation.LiveLocationYouAndOther" = "**You** and %@"; + +"PeopleNearby.MakeVisible" = "Make Myself Visible"; +"PeopleNearby.MakeInvisible" = "Stop Showing Me"; + +"PeopleNearby.ShowMorePeople_0" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_1" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_2" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_3_10" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_many" = "Show %@ More People"; +"PeopleNearby.ShowMorePeople_any" = "Show %@ More People"; + +"PeopleNearby.VisibleUntil" = "visible until %@"; + +"PeopleNearby.MakeVisibleTitle" = "Make Myself Visible"; +"PeopleNearby.MakeVisibleDescription" = "Allow people nearby to view your profile for 24 hours?\n\nYour phone number will remain hidden."; + +"PeopleNearby.DiscoverDescription" = "Exchange contact info with people nearby\nand find new friends."; + +"Time.TomorrowAt" = "tomorrow at %@"; diff --git a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift index f21f09f4a8..173646c596 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift @@ -42,9 +42,15 @@ public enum AnimatedStickerMode { case direct } +public enum AnimatedStickerPlaybackPosition { + case start + case end +} + public enum AnimatedStickerPlaybackMode { case once case loop + case still(AnimatedStickerPlaybackPosition) } private final class AnimatedStickerFrame { @@ -72,6 +78,7 @@ private protocol AnimatedStickerFrameSource: class { var frameCount: Int { get } func takeFrame() -> AnimatedStickerFrame? + func skipToEnd() } private final class AnimatedStickerFrameSourceWrapper { @@ -244,6 +251,9 @@ private final class AnimatedStickerCachedFrameSource: AnimatedStickerFrameSource self.data = data self.dataComplete = complete } + + func skipToEnd() { + } } private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource { @@ -289,6 +299,10 @@ private final class AnimatedStickerDirectFrameSource: AnimatedStickerFrameSource } return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1) } + + func skipToEnd() { + self.currentFrame = self.frameCount - 1 + } } private final class AnimatedStickerFrameQueue { @@ -383,7 +397,7 @@ public final class AnimatedStickerNode: ASDisplayNode { private var renderer: (AnimationRenderer & ASDisplayNode)? - private var isPlaying: Bool = false + public var isPlaying: Bool = false private var canDisplayFirstFrame: Bool = false private var playbackMode: AnimatedStickerPlaybackMode = .loop @@ -456,7 +470,9 @@ public final class AnimatedStickerNode: ASDisplayNode { if let directData = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) { strongSelf.directData = (directData, path, width, height) } - if strongSelf.isPlaying { + if case let .still(position) = playbackMode { + strongSelf.seekTo(position) + } else if strongSelf.isPlaying { strongSelf.play() } else if strongSelf.canDisplayFirstFrame { strongSelf.play(firstFrame: true) @@ -597,11 +613,11 @@ public final class AnimatedStickerNode: ASDisplayNode { self.reportedStarted = false self.timer.swap(nil)?.invalidate() if self.playToCompletionOnStop { - self.seekToStart() + self.seekTo(.start) } } - public func seekToStart() { + public func seekTo(_ position: AnimatedStickerPlaybackPosition) { self.isPlaying = false let directData = self.directData @@ -612,6 +628,9 @@ public final class AnimatedStickerNode: ASDisplayNode { var maybeFrameSource: AnimatedStickerFrameSource? if let directData = directData { maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3) + if position == .end { + maybeFrameSource?.skipToEnd() + } } else if let (cachedData, cachedDataComplete) = cachedData { if #available(iOS 9.0, *) { maybeFrameSource = AnimatedStickerCachedFrameSource(queue: queue, data: cachedData, complete: cachedDataComplete, notifyUpdated: {}) diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 8de824eba8..974cd94fc7 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -59,7 +59,12 @@ public final class CallListController: ViewController { if case .tab = self.mode { self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationCallIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.callPressed)) - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconCalls") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconCalls") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconCalls") + } self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle self.tabBarItem.image = icon self.tabBarItem.selectedImage = icon diff --git a/submodules/Charts/BUCK b/submodules/Charts/BUCK new file mode 100644 index 0000000000..79bf8180b8 --- /dev/null +++ b/submodules/Charts/BUCK @@ -0,0 +1,31 @@ +load("//Config:buck_rule_macros.bzl", "static_library") + +static_library( + name = "Charts", + srcs = glob([ + "Sources/**/*.swift", + ]), + deps = [ + "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", + "//submodules/AsyncDisplayKit:AsyncDisplayKit#shared", + "//submodules/Display:Display#shared", + "//submodules/Postbox:Postbox#shared", + "//submodules/TelegramCore:TelegramCore#shared", + "//submodules/SyncCore:SyncCore#shared", + "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/AccountContext:AccountContext", + "//submodules/ItemListUI:ItemListUI", + "//submodules/AvatarNode:AvatarNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/AlertUI:AlertUI", + "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/TelegramNotices:TelegramNotices", + "//submodules/MergeLists:MergeLists", + "//submodules/AppBundle:AppBundle", + ], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], +) diff --git a/submodules/Charts/Info.plist b/submodules/Charts/Info.plist new file mode 100644 index 0000000000..e1fe4cfb7b --- /dev/null +++ b/submodules/Charts/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift b/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift new file mode 100644 index 0000000000..7232c594c3 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartDetailsView.swift @@ -0,0 +1,258 @@ +// +// ChartDetailsView.swift +// GraphTest +// +// Created by Andrew Solovey on 14/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let cornerRadius: CGFloat = 5 +private let verticalMargins: CGFloat = 8 +private var labelHeight: CGFloat = 18 +private var margin: CGFloat = 10 +private var prefixLabelWidth: CGFloat = 27 +private var textLabelWidth: CGFloat = 60 +private var valueLabelWidth: CGFloat = 65 + +struct ChartDetailsViewModel { + struct Value { + let prefix: String? + let title: String + let value: String + let color: UIColor + let visible: Bool + } + + var title: String + var showArrow: Bool + var showPrefixes: Bool + var values: [Value] + var totalValue: Value? + var tapAction: (() -> Void)? + + static let blank = ChartDetailsViewModel(title: "", showArrow: false, showPrefixes: false, values: [], totalValue: nil, tapAction: nil) +} + +class ChartDetailsView: UIControl { + let titleLabel = UILabel() + let arrowView = UIImageView() + + var prefixViews: [UILabel] = [] + var labelsViews: [UILabel] = [] + var valuesViews: [UILabel] = [] + + private var viewModel: ChartDetailsViewModel? + private var colorMode: ColorMode = .day + + static func fromNib() -> ChartDetailsView { + return Bundle.main.loadNibNamed("ChartDetailsView", owner: nil, options: nil)?.first as! ChartDetailsView + } + + override init(frame: CGRect) { + super.init(frame: frame) + + layer.cornerRadius = cornerRadius + clipsToBounds = true + + addTarget(self, action: #selector(didTap), for: .touchUpInside) + titleLabel.font = UIFont.systemFont(ofSize: 12, weight: .bold) + arrowView.image = UIImage.arrowRight + arrowView.contentMode = .scaleAspectFill + + addSubview(titleLabel) + addSubview(arrowView) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func setup(viewModel: ChartDetailsViewModel, animated: Bool) { + self.viewModel = viewModel + + titleLabel.setText(viewModel.title, animated: animated) + titleLabel.setVisible(!viewModel.title.isEmpty, animated: animated) + arrowView.setVisible(viewModel.showArrow, animated: animated) + + let width: CGFloat = margin * 2 + (viewModel.showPrefixes ? (prefixLabelWidth + margin) : 0) + textLabelWidth + valueLabelWidth + var y: CGFloat = verticalMargins + + if (!viewModel.title.isEmpty || viewModel.showArrow) { + titleLabel.frame = CGRect(x: margin, y: y, width: width, height: labelHeight) + arrowView.frame = CGRect(x: width - 6 - margin, y: margin, width: 6, height: 10) + y += labelHeight + } + let labelsCount: Int = viewModel.values.count + ((viewModel.totalValue == nil) ? 0 : 1) + + setLabelsCount(array: &prefixViews, + count: viewModel.showPrefixes ? labelsCount : 0, + font: UIFont.systemFont(ofSize: 12, weight: .bold)) + setLabelsCount(array: &labelsViews, + count: labelsCount, + font: UIFont.systemFont(ofSize: 12, weight: .regular), + textAlignment: .left) + setLabelsCount(array: &valuesViews, + count: labelsCount, + font: UIFont.systemFont(ofSize: 12, weight: .bold)) + + UIView.perform(animated: animated, animations: { + for (index, value) in viewModel.values.enumerated() { + var x: CGFloat = margin + if viewModel.showPrefixes { + let prefixLabel = self.prefixViews[index] + prefixLabel.textColor = self.colorMode.chartDetailsTextColor + prefixLabel.setText(value.prefix, animated: false) + prefixLabel.frame = CGRect(x: x, y: y, width: prefixLabelWidth, height: labelHeight) + x += prefixLabelWidth + margin + prefixLabel.alpha = value.visible ? 1 : 0 + } + let titleLabel = self.labelsViews[index] + titleLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + titleLabel.setText(value.title, animated: false) + titleLabel.frame = CGRect(x: x, y: y, width: textLabelWidth, height: labelHeight) + titleLabel.alpha = value.visible ? 1 : 0 + x += textLabelWidth + + let valueLabel = self.valuesViews[index] + valueLabel.setTextColor(value.color, animated: false) + valueLabel.setText(value.value, animated: false) + valueLabel.frame = CGRect(x: x, y: y, width: valueLabelWidth, height: labelHeight) + valueLabel.alpha = value.visible ? 1 : 0 + + if value.visible { + y += labelHeight + } + } + if let value = viewModel.totalValue { + var x: CGFloat = margin + if viewModel.showPrefixes { + let prefixLabel = self.prefixViews[viewModel.values.count] + prefixLabel.textColor = self.colorMode.chartDetailsTextColor + prefixLabel.setText(value.prefix, animated: false) + prefixLabel.frame = CGRect(x: x, y: y, width: prefixLabelWidth, height: labelHeight) + prefixLabel.alpha = value.visible ? 1 : 0 + x += prefixLabelWidth + margin + } + let titleLabel = self.labelsViews[viewModel.values.count] + titleLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + titleLabel.setText(value.title, animated: false) + titleLabel.frame = CGRect(x: x, y: y, width: textLabelWidth, height: labelHeight) + titleLabel.alpha = value.visible ? 1 : 0 + x += textLabelWidth + + let valueLabel = self.valuesViews[viewModel.values.count] + valueLabel.setTextColor(self.colorMode.chartDetailsTextColor, animated: false) + valueLabel.setText(value.value, animated: false) + valueLabel.frame = CGRect(x: x, y: y, width: valueLabelWidth, height: labelHeight) + valueLabel.alpha = value.visible ? 1 : 0 + } + }) + } + + override var intrinsicContentSize: CGSize { + if let viewModel = viewModel { + let height = ((!viewModel.title.isEmpty || viewModel.showArrow) ? labelHeight : 0) + + (CGFloat(viewModel.values.filter({ $0.visible }).count) * labelHeight) + + (viewModel.totalValue?.visible == true ? labelHeight : 0) + + verticalMargins * 2 + let width: CGFloat = margin * 2 + + (viewModel.showPrefixes ? (prefixLabelWidth + margin) : 0) + + textLabelWidth + + valueLabelWidth + + return CGSize(width: width, + height: height) + } else { + return CGSize(width: 140, + height: labelHeight + verticalMargins) + } + } + + @objc private func didTap() { + viewModel?.tapAction?() + } + + func setLabelsCount(array: inout [UILabel], + count: Int, + font: UIFont, + textAlignment: NSTextAlignment = .right) { + while array.count > count { + let subview = array.removeLast() + subview.removeFromSuperview() + } + while array.count < count { + let label = UILabel() + label.font = font + label.adjustsFontSizeToFitWidth = true + label.minimumScaleFactor = 0.5 + label.textAlignment = textAlignment + addSubview(label) + array.append(label) + } + } +} + +extension ChartDetailsView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + self.colorMode = colorMode + self.titleLabel.setTextColor(colorMode.chartDetailsTextColor, animated: animated) + if let viewModel = self.viewModel { + self.setup(viewModel: viewModel, animated: animated) + } + UIView.perform(animated: animated) { + self.arrowView.tintColor = colorMode.chartDetailsArrowColor + self.backgroundColor = colorMode.chartDetailsViewColor + } + } +} + +// MARK: UIStackView+removeAllArrangedSubviews +public extension UIStackView { + func setLabelsCount(_ count: Int, + font: UIFont, + huggingPriority: UILayoutPriority, + textAlignment: NSTextAlignment = .right) { + while arrangedSubviews.count > count { + let subview = arrangedSubviews.last! + removeArrangedSubview(subview) + subview.removeFromSuperview() + } + while arrangedSubviews.count < count { + let label = UILabel() + label.font = font + label.textAlignment = textAlignment + label.setContentHuggingPriority(huggingPriority, for: .horizontal) + label.setContentHuggingPriority(huggingPriority, for: .vertical) + label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 999), for: .horizontal) + label.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 999), for: .vertical) + addArrangedSubview(label) + } + } + + func label(at index: Int) -> UILabel { + return arrangedSubviews[index] as! UILabel + } + + func removeAllArrangedSubviews() { + for subview in arrangedSubviews { + removeArrangedSubview(subview) + subview.removeFromSuperview() + } + } +} + +// MARK: UIStackView+addArrangedSubviews +public extension UIStackView { + func addArrangedSubviews(_ views: [UIView]) { + views.forEach({ addArrangedSubview($0) }) + } +} + +// MARK: UIStackView+insertArrangedSubviews +public extension UIStackView { + func insertArrangedSubviews(_ views: [UIView], at index: Int) { + views.reversed().forEach({ insertArrangedSubview($0, at: index) }) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift b/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift new file mode 100644 index 0000000000..bef1a574f4 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartStackSection.swift @@ -0,0 +1,199 @@ +// +// ChartStackSection.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let chartViewHeightFraction: CGFloat = 0.55 +} + +class ChartStackSection: UIView, ColorModeContainer { + var chartView: ChartView + var rangeView: RangeChartView + var visibilityView: ChartVisibilityView + var sectionContainerView: UIView + var separators: [UIView] = [] + + var headerLabel: UILabel! + var titleLabel: UILabel! + var backButton: UIButton! + + var controller: BaseChartController! + + init() { + sectionContainerView = UIView() + chartView = ChartView() + rangeView = RangeChartView() + visibilityView = ChartVisibilityView() + headerLabel = UILabel() + titleLabel = UILabel() + backButton = UIButton() + + super.init(frame: CGRect()) + + self.addSubview(sectionContainerView) + sectionContainerView.addSubview(chartView) + sectionContainerView.addSubview(rangeView) + sectionContainerView.addSubview(visibilityView) + + headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular) + titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) + visibilityView.clipsToBounds = true + backButton.isExclusiveTouch = true + + backButton.setVisible(false, animated: false) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func awakeFromNib() { + super.awakeFromNib() + + headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular) + titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) + visibilityView.clipsToBounds = true + backButton.isExclusiveTouch = true + + backButton.setVisible(false, animated: false) + } + + func apply(colorMode: ColorMode, animated: Bool) { + UIView.perform(animated: animated && self.isVisibleInWindow) { + self.backgroundColor = colorMode.tableBackgroundColor + + self.sectionContainerView.backgroundColor = colorMode.chartBackgroundColor + self.rangeView.backgroundColor = colorMode.chartBackgroundColor + self.visibilityView.backgroundColor = colorMode.chartBackgroundColor + + self.backButton.tintColor = colorMode.actionButtonColor + self.backButton.setTitleColor(colorMode.actionButtonColor, for: .normal) + + for separator in self.separators { + separator.backgroundColor = colorMode.tableSeparatorColor + } + } + + if rangeView.isVisibleInWindow || chartView.isVisibleInWindow { + chartView.loadDetailsViewIfNeeded() + chartView.apply(colorMode: colorMode, animated: animated && chartView.isVisibleInWindow) + controller.apply(colorMode: colorMode, animated: animated) + rangeView.apply(colorMode: colorMode, animated: animated && rangeView.isVisibleInWindow) + } else { + DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval.random(in: 0...0.1)) { + self.chartView.loadDetailsViewIfNeeded() + self.controller.apply(colorMode: colorMode, animated: false) + self.chartView.apply(colorMode: colorMode, animated: false) + self.rangeView.apply(colorMode: colorMode, animated: false) + } + } + + self.titleLabel.setTextColor(colorMode.chartTitleColor, animated: animated && titleLabel.isVisibleInWindow) + self.headerLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && headerLabel.isVisibleInWindow) + } + + @IBAction func didTapBackButton() { + controller.didTapZoomOut() + } + + func setBackButtonVisible(_ visible: Bool, animated: Bool) { + backButton.setVisible(visible, animated: animated) + layoutIfNeeded(animated: animated) + } + + func updateToolViews(animated: Bool) { + rangeView.setRange(controller.currentChartHorizontalRangeFraction, animated: animated) + rangeView.setRangePaging(enabled: controller.isChartRangePagingEnabled, + minimumSize: controller.minimumSelectedChartRange) + visibilityView.setVisible(controller.drawChartVisibity, animated: animated) + if controller.drawChartVisibity { + visibilityView.isExpanded = true + visibilityView.items = controller.actualChartsCollection.chartValues.map { value in + return ChartVisibilityItem(title: value.name, color: value.color) + } + visibilityView.setItemsSelection(controller.actualChartVisibility) + visibilityView.setNeedsLayout() + visibilityView.layoutIfNeeded() + } else { + visibilityView.isExpanded = false + } + superview?.superview?.layoutIfNeeded(animated: animated) + } + + override func layoutSubviews() { + super.layoutSubviews() + + let bounds = self.bounds + self.sectionContainerView.frame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: 350.0)) + self.chartView.frame = CGRect(origin: CGPoint(), size: CGSize(width: bounds.width, height: 250.0)) + self.rangeView.frame = CGRect(origin: CGPoint(x: 0.0, y: 250.0), size: CGSize(width: bounds.width, height: 48.0)) + self.visibilityView.frame = CGRect(origin: CGPoint(x: 0.0, y: 308.0), size: CGSize(width: bounds.width, height: 122.0)) + } + + func setup(controller: BaseChartController, title: String) { + self.controller = controller + self.headerLabel.text = title + + // Chart + chartView.renderers = controller.mainChartRenderers + chartView.userDidSelectCoordinateClosure = { [unowned self] point in + self.controller.chartInteractionDidBegin(point: point) + } + chartView.userDidDeselectCoordinateClosure = { [unowned self] in + self.controller.chartInteractionDidEnd() + } + controller.cartViewBounds = { [unowned self] in + return self.chartView.bounds + } + controller.chartFrame = { [unowned self] in + return self.chartView.chartFrame + } + controller.setDetailsViewModel = { [unowned self] viewModel, animated in + self.chartView.setDetailsViewModel(viewModel: viewModel, animated: animated) + } + controller.setDetailsChartVisibleClosure = { [unowned self] visible, animated in + self.chartView.setDetailsChartVisible(visible, animated: animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] position in + self.chartView.detailsViewPosition = position + } + controller.setChartTitleClosure = { [unowned self] title, animated in + self.titleLabel.setText(title, animated: animated) + } + controller.setBackButtonVisibilityClosure = { [unowned self] visible, animated in + self.setBackButtonVisible(visible, animated: animated) + } + controller.refreshChartToolsClosure = { [unowned self] animated in + self.updateToolViews(animated: animated) + } + + // Range view + rangeView.chartView.renderers = controller.navigationRenderers + rangeView.rangeDidChangeClosure = { range in + controller.updateChartRange(range) + } + rangeView.touchedOutsideClosure = { + controller.cancelChartInteraction() + } + controller.chartRangeUpdatedClosure = { [unowned self] (range, animated) in + self.rangeView.setRange(range, animated: animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.rangeView.setRangePaging(enabled: isEnabled, minimumSize: pageSize) + } + + // Visibility view + visibilityView.selectionCallbackClosure = { [unowned self] visibility in + self.controller.updateChartsVisibility(visibility: visibility, animated: true) + } + + controller.initializeChart() + updateToolViews(animated: false) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib b/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib new file mode 100644 index 0000000000..fc883dd96c --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartStackSection.xib @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/submodules/Charts/Sources/Chart Screen/ChartView.swift b/submodules/Charts/Sources/Chart Screen/ChartView.swift new file mode 100644 index 0000000000..39b93d9fa0 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartView.swift @@ -0,0 +1,158 @@ +// +// ChartView.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +public protocol ChartViewRenderer: class { + var containerViews: [UIView] { get set } + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) +} + +class ChartView: UIView { + override init(frame: CGRect) { + super.init(frame: frame) + + setupView() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + setupView() + } + + var chartInsets: UIEdgeInsets = UIEdgeInsets(top: 40, left: 16, bottom: 35, right: 16) { + didSet { + setNeedsDisplay() + } + } + + var renderers: [ChartViewRenderer] = [] { + willSet { + renderers.forEach { $0.containerViews.removeAll(where: { $0 == self }) } + } + didSet { + renderers.forEach { $0.containerViews.append(self) } + setNeedsDisplay() + } + } + + var chartFrame: CGRect { + let chartBound = self.bounds + return CGRect(x: chartInsets.left, + y: chartInsets.top, + width: max(1, chartBound.width - chartInsets.left - chartInsets.right), + height: max(1, chartBound.height - chartInsets.top - chartInsets.bottom)) + } + + override func draw(_ rect: CGRect) { + guard let context = UIGraphicsGetCurrentContext() else { return } + let chartBounds = self.bounds + let chartFrame = self.chartFrame + + for renderer in renderers { + renderer.render(context: context, bounds: chartBounds, chartFrame: chartFrame) + } + } + + var userDidSelectCoordinateClosure: ((CGPoint) -> Void)? + var userDidDeselectCoordinateClosure: (() -> Void)? + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + if let point = touches.first?.location(in: self) { + let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width, + y: (point.y - chartFrame.origin.y) / chartFrame.height) + userDidSelectCoordinateClosure?(fractionPoint) + } + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + if let point = touches.first?.location(in: self) { + let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width, + y: (point.y - chartFrame.origin.y) / chartFrame.height) + userDidSelectCoordinateClosure?(fractionPoint) + } + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + userDidDeselectCoordinateClosure?() + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + userDidDeselectCoordinateClosure?() + } + + // MARK: Details View + + private var detailsView: ChartDetailsView! + private var maxDetailsViewWidth: CGFloat = 0 + func loadDetailsViewIfNeeded() { + if detailsView == nil { + let detailsView = ChartDetailsView(frame: bounds) + addSubview(detailsView) + detailsView.alpha = 0 + self.detailsView = detailsView + } + } + + private var detailsTableTopOffset: CGFloat = 5 + private var detailsTableLeftOffset: CGFloat = 8 + private var isDetailsViewVisible: Bool = false + + var detailsViewPosition: CGFloat = 0 { + didSet { + loadDetailsViewIfNeeded() + let detailsViewSize = detailsView.intrinsicContentSize + maxDetailsViewWidth = max(maxDetailsViewWidth, detailsViewSize.width) + if maxDetailsViewWidth + detailsTableLeftOffset > detailsViewPosition { + detailsView.frame = CGRect(x: min(detailsViewPosition + detailsTableLeftOffset, bounds.width - maxDetailsViewWidth), + y: chartInsets.top + detailsTableTopOffset, + width: maxDetailsViewWidth, + height: detailsViewSize.height) + } else { + detailsView.frame = CGRect(x: detailsViewPosition - maxDetailsViewWidth - detailsTableLeftOffset, + y: chartInsets.top + detailsTableTopOffset, + width: maxDetailsViewWidth, + height: detailsViewSize.height) + } + } + } + + func setDetailsChartVisible(_ visible: Bool, animated: Bool) { + guard isDetailsViewVisible != visible else { + return + } + isDetailsViewVisible = visible + loadDetailsViewIfNeeded() + detailsView.setVisible(visible, animated: animated) + if !visible { + maxDetailsViewWidth = 0 + } + } + + func setDetailsViewModel(viewModel: ChartDetailsViewModel, animated: Bool) { + loadDetailsViewIfNeeded() + detailsView.setup(viewModel: viewModel, animated: animated) + UIView.perform(animated: animated, animations: { + let position = self.detailsViewPosition + self.detailsViewPosition = position + }) + } + + func setupView() { + backgroundColor = .clear + layer.drawsAsynchronously = true + } +} + + +extension ChartView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + detailsView?.apply(colorMode: colorMode, animated: animated && (detailsView?.isVisibleInWindow ?? false)) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift b/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift new file mode 100644 index 0000000000..2476526f1a --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartVisibilityItemView.swift @@ -0,0 +1,95 @@ +// +// ChartVisibilityItemCell.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartVisibilityItemView: UIView { + static let textFont = UIFont.systemFont(ofSize: 14, weight: .medium) + + let checkButton: UIButton = UIButton(type: .system) + + override init(frame: CGRect) { + super.init(frame: frame) + + setupView() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func awakeFromNib() { + super.awakeFromNib() + setupView() + } + + func setupView() { + checkButton.frame = bounds + checkButton.titleLabel?.font = ChartVisibilityItemView.textFont + checkButton.layer.cornerRadius = 6 + checkButton.layer.masksToBounds = true + checkButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside) + let pressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(didRecognizedLongPress(recognizer:))) + pressRecognizer.cancelsTouchesInView = true + checkButton.addGestureRecognizer(pressRecognizer) + addSubview(checkButton) + } + + var tapClosure: (() -> Void)? + var longTapClosure: (() -> Void)? + + private func updateStyle(animated: Bool) { + guard let item = item else { + return + } + UIView.perform(animated: animated, animations: { + if self.isChecked { + self.checkButton.setTitleColor(.white, for: .normal) + self.checkButton.backgroundColor = item.color + self.checkButton.layer.borderColor = nil + self.checkButton.layer.borderWidth = 0 + self.checkButton.setTitle("✓ " + item.title, for: .normal) + } else { + self.checkButton.backgroundColor = .clear + self.checkButton.layer.borderColor = item.color.cgColor + self.checkButton.layer.borderWidth = 1 + self.checkButton.setTitleColor(item.color, for: .normal) + self.checkButton.setTitle(item.title, for: .normal) + } + + }) + } + + override func layoutSubviews() { + super.layoutSubviews() + + checkButton.frame = bounds + } + + @objc private func didTapButton() { + tapClosure?() + } + + @objc private func didRecognizedLongPress(recognizer: UIGestureRecognizer) { + if recognizer.state == .began { + longTapClosure?() + } + } + + var item: ChartVisibilityItem? = nil { + didSet { + updateStyle(animated: false) + } + } + + private(set) var isChecked: Bool = true + func setChecked(isChecked: Bool, animated: Bool) { + self.isChecked = isChecked + updateStyle(animated: true) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift b/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift new file mode 100644 index 0000000000..fda3c3901f --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartVisibilityView.swift @@ -0,0 +1,147 @@ +// +// ChartVisibilityView.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let itemHeight: CGFloat = 30 + static let itemSpacing: CGFloat = 8 + static let labelTextApproxInsets: CGFloat = 40 + static let insets = UIEdgeInsets(top: 0, left: 16, bottom: 16, right: 16) +} + +struct ChartVisibilityItem { + var title: String + var color: UIColor +} + +class ChartVisibilityView: UIView { + var items: [ChartVisibilityItem] = [] { + didSet { + selectedItems = items.map { _ in true } + while selectionViews.count > selectedItems.count { + selectionViews.last?.removeFromSuperview() + selectionViews.removeLast() + } + while selectionViews.count < selectedItems.count { + let view = ChartVisibilityItemView(frame: bounds) + addSubview(view) + selectionViews.append(view) + } + + for (index, item) in items.enumerated() { + let view = selectionViews[index] + view.item = item + view.tapClosure = { [weak self] in + guard let self = self else { return } + self.setItemSelected(!self.selectedItems[index], at: index, animated: true) + self.notifyItemSelection() + } + + view.longTapClosure = { [weak self] in + guard let self = self else { return } + let hasSelectedItem = self.selectedItems.enumerated().contains(where: { $0.element && $0.offset != index }) + if hasSelectedItem { + for (itemIndex, _) in self.items.enumerated() { + self.setItemSelected(itemIndex == index, at: itemIndex, animated: true) + } + } else { + for (itemIndex, _) in self.items.enumerated() { + self.setItemSelected(true, at: itemIndex, animated: true) + } + } + self.notifyItemSelection() + } + } + } + } + + private (set) var selectedItems: [Bool] = [] + var isExpanded: Bool = true { + didSet { + invalidateIntrinsicContentSize() + setNeedsUpdateConstraints() + } + } + + private var selectionViews: [ChartVisibilityItemView] = [] + + private func generateItemsFrames(frame: CGRect) -> [CGRect] { + var previousPoint = CGPoint(x: Constants.insets.left, y: Constants.insets.top) + var frames: [CGRect] = [] + + for item in items { + let labelSize = (item.title as NSString).size(withAttributes: [.font: ChartVisibilityItemView.textFont]) + let width = (labelSize.width + Constants.labelTextApproxInsets).rounded(.up) + if previousPoint.x + width < (frame.width - Constants.insets.left - Constants.insets.right) { + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } else if previousPoint.x <= Constants.insets.left { + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } else { + previousPoint.y += Constants.itemHeight + Constants.itemSpacing + previousPoint.x = Constants.insets.left + frames.append(CGRect(origin: previousPoint, size: CGSize(width: width, height: Constants.itemHeight))) + } + previousPoint.x += width + Constants.itemSpacing + } + + return frames + } + + var selectionCallbackClosure: (([Bool]) -> Void)? + + func setItemSelected(_ selected: Bool, at index: Int, animated: Bool) { + self.selectedItems[index] = selected + self.selectionViews[index].setChecked(isChecked: selected, animated: animated) + } + + func setItemsSelection(_ selection: [Bool]) { + assert(selection.count == items.count) + self.selectedItems = selection + for (index, selected) in self.selectedItems.enumerated() { + selectionViews[index].setChecked(isChecked: selected, animated: false) + } + } + + private func notifyItemSelection() { + selectionCallbackClosure?(selectedItems) + } + + override func layoutSubviews() { + super.layoutSubviews() + + updateFrames() + } + + private func updateFrames() { + for (index, frame) in generateItemsFrames(frame: bounds).enumerated() { + selectionViews[index].frame = frame + } + } + + override var intrinsicContentSize: CGSize { + guard isExpanded else { + var size = self.bounds.size + size.height = 0 + return size + } + let frames = generateItemsFrames(frame: UIScreen.main.bounds) + guard let lastFrame = frames.last else { return .zero } + let size = CGSize(width: frame.width, height: lastFrame.maxY + Constants.insets.bottom) + return size + } +} + +extension ChartVisibilityView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + UIView.perform(animated: animated) { + self.backgroundColor = colorMode.chartBackgroundColor + self.tintColor = colorMode.descriptionActionColor + } + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift b/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift new file mode 100644 index 0000000000..085e4689bd --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartsDataLoader.swift @@ -0,0 +1,51 @@ +// +// ChartsDataLoader.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +enum ChartsDataType: String { + case generalLines = "1" + case twoAxisLines = "2" + case stackedBars = "3" + case dailyBars = "4" + case percentPie = "5" +} + +private enum Constants { + static let overviewFilename = "overview.json" + static let dataDir = "data" +} + +class ChartsDataLoader { + static var documentDirectoryURL: URL { + let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) + let documentsDirectory = paths[0] + return documentsDirectory + } + + static func overviewData(type: ChartsDataType, extraCopiesCount: Int = 0, sync: Bool = false, success: @escaping (ChartsCollection) -> Void) { + let path = Bundle.main.bundleURL + .appendingPathComponent(Constants.dataDir) + .appendingPathComponent(type.rawValue) + .appendingPathComponent(Constants.overviewFilename) + ChartsDataManager().readChart(file: path, extraCopiesCount: extraCopiesCount, sync: sync, success: success, failure: { _ in }) + } + + static func detaildData(type: ChartsDataType, extraCopiesCount: Int = 0, date: Date, success: @escaping (ChartsCollection) -> Void, failure: @escaping (Error) -> Void) { + let dateComponents = Calendar.utc.dateComponents([.day, .month, .year], from: date) + let yearMonth = String(format: "%04d-%02d", dateComponents.year ?? 0, dateComponents.month ?? 0) + let day = String(format: "%02d.json", dateComponents.day ?? 0) + + let path = Bundle.main.bundleURL + .appendingPathComponent(Constants.dataDir) + .appendingPathComponent(type.rawValue) + .appendingPathComponent(yearMonth) + .appendingPathComponent(day) + ChartsDataManager().readChart(file: path, extraCopiesCount: extraCopiesCount, sync: false, success: success, failure: failure) + } +} diff --git a/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift b/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift new file mode 100644 index 0000000000..e8c22e6453 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/ChartsStackViewController.swift @@ -0,0 +1,222 @@ +// +// ChartsStackViewController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartsStackViewController: UIViewController { + @IBOutlet private var stackView: UIStackView! + @IBOutlet private var scrollView: UIScrollView! + @IBOutlet private var psLabel: UILabel! + @IBOutlet private var ppsLabel: UILabel! + @IBOutlet private var animationButton: ChartVisibilityItemView! + + private var sections: [ChartStackSection] = [] + + private var colorMode: ColorMode = .night + private var colorModeButton: UIBarButtonItem! + private var performFastAnimation: Bool = false + + override func viewDidLoad() { + super.viewDidLoad() + + title = "Statistics" + colorModeButton = UIBarButtonItem(title: colorMode.switchTitle, style: .plain, target: self, action: #selector(didTapSwitchColorMode)) + navigationItem.rightBarButtonItem = colorModeButton + + apply(colorMode: colorMode, animated: false) + + self.navigationController?.navigationBar.barStyle = .black + self.navigationController?.navigationBar.isTranslucent = false + + self.view.isUserInteractionEnabled = false + animationButton.backgroundColor = .clear + animationButton.tapClosure = { [weak self] in + guard let self = self else { return } + self.setSlowAnimationEnabled(!self.animationButton.isChecked) + } + self.setSlowAnimationEnabled(false) + + loadChart1() + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + DispatchQueue.main.async { + self.view.setNeedsUpdateConstraints() + self.view.setNeedsLayout() + } + } + + func loadChart1() { + ChartsDataLoader.overviewData(type: .generalLines, sync: true, success: { collection in + let generalLinesChartController = GeneralLinesChartController(chartsCollection: collection) + self.addSection(controller: generalLinesChartController, title: "FOLLOWERS") + generalLinesChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .generalLines, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart2() + } + }) + } + + func loadChart2() { + ChartsDataLoader.overviewData(type: .twoAxisLines, success: { collection in + let twoAxisLinesChartController = TwoAxisLinesChartController(chartsCollection: collection) + self.addSection(controller: twoAxisLinesChartController, title: "INTERACTIONS") + twoAxisLinesChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .twoAxisLines, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart3() + } + }) + } + + func loadChart3() { + ChartsDataLoader.overviewData(type: .stackedBars, success: { collection in + let stackedBarsChartController = StackedBarsChartController(chartsCollection: collection) + self.addSection(controller: stackedBarsChartController, title: "FRUITS") + stackedBarsChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .stackedBars, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart4() + } + }) + } + + func loadChart4() { + ChartsDataLoader.overviewData(type: .dailyBars, success: { collection in + let dailyBarsChartController = DailyBarsChartController(chartsCollection: collection) + self.addSection(controller: dailyBarsChartController, title: "VIEWS") + dailyBarsChartController.getDetailsData = { date, completion in + ChartsDataLoader.detaildData(type: .dailyBars, date: date, success: { collection in + completion(collection) + }, failure: { error in + completion(nil) + }) + } + DispatchQueue.main.async { + self.loadChart5() + } + }) + } + + func loadChart5() { + ChartsDataLoader.overviewData(type: .percentPie, success: { collection in + let percentPieChartController = PercentPieChartController(chartsCollection: collection) + self.addSection(controller: percentPieChartController, title: "MORE FRUITS") + self.finalizeChartsLoading() + }) + } + + func setSlowAnimationEnabled(_ isEnabled: Bool) { + animationButton.setChecked(isChecked: isEnabled, animated: true) + if isEnabled { + TimeInterval.animationDurationMultipler = 5 + } else { + TimeInterval.animationDurationMultipler = 1 + } + } + + func finalizeChartsLoading() { + self.view.isUserInteractionEnabled = true + } + + func addSection(controller: BaseChartController, title: String) { + let section = Bundle.main.loadNibNamed("ChartStackSection", owner: nil, options: nil)?.first as! ChartStackSection + section.frame = UIScreen.main.bounds + section.layoutIfNeeded() + section.setup(controller: controller, title: title) + section.apply(colorMode: colorMode, animated: false) + stackView.addArrangedSubview(section) + sections.append(section) + } + + override var preferredStatusBarStyle: UIStatusBarStyle { + return (colorMode == .day) ? .default : .lightContent + } + + override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { + return .fade + } + + @objc private func didTapSwitchColorMode() { + self.colorMode = self.colorMode == .day ? .night : .day + apply(colorMode: self.colorMode, animated: !performFastAnimation) + colorModeButton.title = colorMode.switchTitle + } +} + +extension ChartsStackViewController: UIScrollViewDelegate { + func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { + performFastAnimation = decelerate + } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + performFastAnimation = false + } +} + +extension ChartsStackViewController: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + + UIView.perform(animated: animated) { + self.psLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && self.psLabel.isVisibleInWindow) + self.ppsLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && self.ppsLabel.isVisibleInWindow) + self.animationButton.item = ChartVisibilityItem(title: "Enable slow animations", + color: colorMode.sectionTitleColor) + + self.view.backgroundColor = colorMode.tableBackgroundColor + + if (animated) { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.navigationController?.navigationBar.layer.add(animation, forKey: "kCATransitionColorFade") + } + + self.navigationController?.navigationBar.tintColor = colorMode.actionButtonColor + self.navigationController?.navigationBar.barTintColor = colorMode.chartBackgroundColor + self.navigationController?.navigationBar.titleTextAttributes = [.font: UIFont.systemFont(ofSize: 17, weight: .medium), + .foregroundColor: colorMode.viewTintColor] + self.view.layoutIfNeeded() + } + self.setNeedsStatusBarAppearanceUpdate() + + for section in sections { + section.apply(colorMode: colorMode, animated: animated && section.isVisibleInWindow) + } + } +} + +extension ColorMode { + var switchTitle: String { + switch self { + case .day: + return "Night Mode" + case .night: + return "Day Mode" + } + } +} diff --git a/submodules/Charts/Sources/Chart Screen/RangeChartView.swift b/submodules/Charts/Sources/Chart Screen/RangeChartView.swift new file mode 100644 index 0000000000..91089c1de8 --- /dev/null +++ b/submodules/Charts/Sources/Chart Screen/RangeChartView.swift @@ -0,0 +1,291 @@ +// +// RangeChartView.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// +import UIKit + +private enum Constants { + static let cropIndocatorLineWidth: CGFloat = 1 + static let markerSelectionRange: CGFloat = 25 + static let defaultMinimumRangeDistance: CGFloat = 0.05 + static let titntAreaWidth: CGFloat = 10 + static let horizontalContentMargin: CGFloat = 16 + static let cornerRadius: CGFloat = 5 +} + +class RangeChartView: UIControl { + private enum Marker { + case lower + case upper + case center + } + public var lowerBound: CGFloat = 0 { + didSet { + setNeedsLayout() + } + } + public var upperBound: CGFloat = 1 { + didSet { + setNeedsLayout() + } + } + public var selectionColor: UIColor = .blue + public var defaultColor: UIColor = .lightGray + + public var minimumRangeDistance: CGFloat = Constants.defaultMinimumRangeDistance + + private let lowerBoundTintView = UIView() + private let upperBoundTintView = UIView() + private let cropFrameView = UIImageView() + + private var selectedMarker: Marker? + private var selectedMarkerHorizontalOffet: CGFloat = 0 + private var isBoundCropHighlighted: Bool = false + private var isRangePagingEnabled: Bool = false + + public let chartView = ChartView() + + override init(frame: CGRect) { + super.init(frame: frame) + + layoutMargins = UIEdgeInsets(top: Constants.cropIndocatorLineWidth, + left: Constants.horizontalContentMargin, + bottom: Constants.cropIndocatorLineWidth, + right: Constants.horizontalContentMargin) + + self.setup() + } + + func setup() { + isMultipleTouchEnabled = false + + chartView.chartInsets = .zero + chartView.backgroundColor = .clear + + addSubview(chartView) + addSubview(lowerBoundTintView) + addSubview(upperBoundTintView) + addSubview(cropFrameView) + cropFrameView.isUserInteractionEnabled = false + chartView.isUserInteractionEnabled = false + lowerBoundTintView.isUserInteractionEnabled = false + upperBoundTintView.isUserInteractionEnabled = false + + chartView.layer.cornerRadius = 5 + upperBoundTintView.layer.cornerRadius = 5 + lowerBoundTintView.layer.cornerRadius = 5 + + chartView.layer.masksToBounds = true + upperBoundTintView.layer.masksToBounds = true + lowerBoundTintView.layer.masksToBounds = true + + layoutViews() + } + + override func awakeFromNib() { + super.awakeFromNib() + + self.setup() + } + + public var rangeDidChangeClosure: ((ClosedRange) -> Void)? + public var touchedOutsideClosure: (() -> Void)? + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + func setRangePaging(enabled: Bool, minimumSize: CGFloat) { + isRangePagingEnabled = enabled + minimumRangeDistance = minimumSize + } + + func setRange(_ range: ClosedRange, animated: Bool) { + UIView.perform(animated: animated) { + self.lowerBound = range.lowerBound + self.upperBound = range.upperBound + self.layoutIfNeeded() + } + } + + override func layoutSubviews() { + super.layoutSubviews() + + layoutViews() + } + + override var isEnabled: Bool { + get { + return super.isEnabled + } + set { + if newValue == false { + selectedMarker = nil + } + super.isEnabled = newValue + } + } + + // MARK: - Touches + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let point = touches.first?.location(in: self) else { return } + + if abs(locationInView(for: upperBound) - point.x + Constants.markerSelectionRange / 2) < Constants.markerSelectionRange { + selectedMarker = .upper + selectedMarkerHorizontalOffet = point.x - locationInView(for: upperBound) + isBoundCropHighlighted = true + } else if abs(locationInView(for: lowerBound) - point.x - Constants.markerSelectionRange / 2) < Constants.markerSelectionRange { + selectedMarker = .lower + selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound) + isBoundCropHighlighted = true + } else if point.x > locationInView(for: lowerBound) && point.x < locationInView(for: upperBound) { + selectedMarker = .center + selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound) + isBoundCropHighlighted = true + } else { + selectedMarker = nil + return + } + + sendActions(for: .touchDown) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let selectedMarker = selectedMarker else { return } + guard let point = touches.first?.location(in: self) else { return } + + let horizontalPosition = point.x - selectedMarkerHorizontalOffet + let fraction = fractionFor(offsetX: horizontalPosition) + updateMarkerOffset(selectedMarker, fraction: fraction) + + sendActions(for: .valueChanged) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + guard isEnabled else { return } + guard let selectedMarker = selectedMarker else { + touchedOutsideClosure?() + return + } + guard let point = touches.first?.location(in: self) else { return } + + let horizontalPosition = point.x - selectedMarkerHorizontalOffet + let fraction = fractionFor(offsetX: horizontalPosition) + updateMarkerOffset(selectedMarker, fraction: fraction) + + self.selectedMarker = nil + self.isBoundCropHighlighted = false + if bounds.contains(point) { + sendActions(for: .touchUpInside) + } else { + sendActions(for: .touchUpOutside) + } + rangeDidChangeClosure?(lowerBound...upperBound) + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + self.selectedMarker = nil + self.isBoundCropHighlighted = false + sendActions(for: .touchCancel) + } +} + +private extension RangeChartView { + var contentFrame: CGRect { + return CGRect(x: layoutMargins.right, + y: layoutMargins.top, + width: (bounds.width - layoutMargins.right - layoutMargins.left), + height: bounds.height - layoutMargins.top - layoutMargins.bottom) + } + + func locationInView(for fraction: CGFloat) -> CGFloat { + return contentFrame.minX + contentFrame.width * fraction + } + + func locationInView(for fraction: Double) -> CGFloat { + return locationInView(for: CGFloat(fraction)) + } + + func fractionFor(offsetX: CGFloat) -> CGFloat { + guard contentFrame.width > 0 else { + return 0 + } + + return crop(0, CGFloat((offsetX - contentFrame.minX ) / contentFrame.width), 1) + } + + private func updateMarkerOffset(_ marker: Marker, fraction: CGFloat, notifyDelegate: Bool = true) { + let fractionToCount: CGFloat + if isRangePagingEnabled { + guard let minValue = stride(from: CGFloat(0.0), through: CGFloat(1.0), by: minimumRangeDistance).min(by: { abs($0 - fraction) < abs($1 - fraction) }) else { return } + fractionToCount = minValue + } else { + fractionToCount = fraction + } + + switch marker { + case .lower: + lowerBound = min(fractionToCount, upperBound - minimumRangeDistance) + case .upper: + upperBound = max(fractionToCount, lowerBound + minimumRangeDistance) + case .center: + let distance = upperBound - lowerBound + lowerBound = max(0, min(fractionToCount, 1 - distance)) + upperBound = lowerBound + distance + } + if notifyDelegate { + rangeDidChangeClosure?(lowerBound...upperBound) + } + UIView.animate(withDuration: isRangePagingEnabled ? 0.1 : 0) { + self.layoutIfNeeded() + } + } + + // MARK: - Layout + + func layoutViews() { + cropFrameView.frame = CGRect(x: locationInView(for: lowerBound), + y: contentFrame.minY - Constants.cropIndocatorLineWidth, + width: locationInView(for: upperBound) - locationInView(for: lowerBound), + height: contentFrame.height + Constants.cropIndocatorLineWidth * 2) + + if chartView.frame != contentFrame { + chartView.frame = contentFrame + } + + lowerBoundTintView.frame = CGRect(x: contentFrame.minX, + y: contentFrame.minY, + width: max(0, locationInView(for: lowerBound) - contentFrame.minX + Constants.titntAreaWidth), + height: contentFrame.height) + + upperBoundTintView.frame = CGRect(x: locationInView(for: upperBound) - Constants.titntAreaWidth, + y: contentFrame.minY, + width: max(0, contentFrame.maxX - locationInView(for: upperBound) + Constants.titntAreaWidth), + height: contentFrame.height) + } +} + +extension RangeChartView: ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) { + let colusre = { + self.lowerBoundTintView.backgroundColor = colorMode.rangeViewTintColor + self.upperBoundTintView.backgroundColor = colorMode.rangeViewTintColor + } + + self.cropFrameView.setImage(colorMode.rangeCropImage, animated: animated) + + // self.chartView.apply(colorMode: colorMode, animated: animated) + + if animated { + UIView.animate(withDuration: .defaultDuration, animations: colusre) + } else { + colusre() + } + } +} diff --git a/submodules/Charts/Sources/ChartNode.swift b/submodules/Charts/Sources/ChartNode.swift new file mode 100644 index 0000000000..b6c6da436c --- /dev/null +++ b/submodules/Charts/Sources/ChartNode.swift @@ -0,0 +1,48 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import AppBundle + +public final class ChartNode: ASDisplayNode { + private var chartView: ChartStackSection { + return self.view as! ChartStackSection + } + + public override init() { + super.init() + + self.setViewBlock({ + return ChartStackSection() + }) + } + + public override func didLoad() { + super.didLoad() + + self.view.disablesInteractiveTransitionGestureRecognizer = true + } + + public func setup(_ data: String, bar: Bool = false) { + if let data = data.data(using: .utf8) { + ChartsDataManager().readChart(data: data, extraCopiesCount: 0, sync: true, success: { [weak self] collection in + let controller: BaseChartController + if bar { + controller = DailyBarsChartController(chartsCollection: collection) + } else { + controller = GeneralLinesChartController(chartsCollection: collection) + } + if let strongSelf = self { + strongSelf.chartView.setup(controller: controller, title: "") + strongSelf.chartView.apply(colorMode: .day, animated: false) + } + }) { error in + + } + } + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift b/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift new file mode 100644 index 0000000000..f3ecd8215d --- /dev/null +++ b/submodules/Charts/Sources/Charts Reader/ChartsCollection.swift @@ -0,0 +1,91 @@ +// +// ChardData.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation +import UIKit + +struct ChartsCollection { + struct Chart { + var color: UIColor + var name: String + var values: [Double] + } + + var axisValues: [Date] + var chartValues: [Chart] + + static let blank = ChartsCollection(axisValues: [], chartValues: []) + var isBlank: Bool { + return axisValues.isEmpty || chartValues.isEmpty + } +} + +extension ChartsCollection { + public init(from decodedData: [String: Any]) throws { + guard let columns = decodedData["columns"] as? [[Any]] else { + throw ChartsError.generalConversion("Unable to get columns from: \(decodedData)") + } + guard let types = decodedData["types"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get types from: \(decodedData)") + } + guard let names = decodedData["names"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get names from: \(decodedData)") + } + guard let colors = decodedData["colors"] as? [String: String] else { + throw ChartsError.generalConversion("Unable to get colors from: \(decodedData)") + } + +// chart.colors – Color for each variable in 6-hex-digit format (e.g. "#AAAAAA"). +// chart.names – Name for each variable. +// chart.percentage – true for percentage based values. +// chart.stacked – true for values stacking on top of each other. +// chart.y_scaled – true for charts with 2 Y axes. + + var axixValuesToSetup: [Date] = [] + var chartToSetup: [Chart] = [] + for column in columns { + guard let columnId = column.first as? String else { + throw ChartsError.generalConversion("Unable to get column name from: \(column)") + } + guard let typeString = types[columnId], let type = ColumnType(rawValue: typeString) else { + throw ChartsError.generalConversion("Unable to get column type from: \(types) - \(columnId)") + } + switch type { + case .axix: + axixValuesToSetup = try column.dropFirst().map { Date(timeIntervalSince1970: try Convert.doubleFrom($0) / 1000) } + case .chart, .bar, .area: + guard let colorString = colors[columnId], + let color = UIColor(hexString: colorString) else { + throw ChartsError.generalConversion("Unable to get color name from: \(colors) - \(columnId)") + } + guard let name = names[columnId] else { + throw ChartsError.generalConversion("Unable to get column name from: \(names) - \(columnId)") + } + let values = try column.dropFirst().map { try Convert.doubleFrom($0) } + chartToSetup.append(Chart(color: color, + name: name, + values: values)) + } + } + + guard axixValuesToSetup.isEmpty == false, + chartToSetup.isEmpty == false, + chartToSetup.firstIndex(where: { $0.values.count != axixValuesToSetup.count }) == nil else { + throw ChartsError.generalConversion("Saniazing: Invalid number of items: \(axixValuesToSetup), \(chartToSetup)") + } + self.axisValues = axixValuesToSetup + self.chartValues = chartToSetup + } +} + +private enum ColumnType: String { + case axix = "x" + case chart = "line" + case area = "area" + case bar = "bar" +} diff --git a/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift b/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift new file mode 100644 index 0000000000..1a32f9bcee --- /dev/null +++ b/submodules/Charts/Sources/Charts Reader/ChartsDataManager.swift @@ -0,0 +1,191 @@ +// +// ChartsDataManager.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +class ChartsDataManager { + func readChart(item: [String: Any], extraCopiesCount: Int = 0, sync: Bool, success: @escaping (ChartsCollection) -> Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let item = decoded as? [String: Any] else { + throw ChartsError.invalidJson + } + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let data = try Data(contentsOf: file) + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let item = decoded as? [String: Any] else { + throw ChartsError.invalidJson + } + var collection = try ChartsCollection(from: item) + for _ in 0.. Void, failure: @escaping (Error) -> Void) { + let workItem: (() -> Void) = { + do { + let data = try Data(contentsOf: file) + let decoded = try JSONSerialization.jsonObject(with: data, options: []) + guard let items = decoded as? [[String: Any]] else { + throw ChartsError.invalidJson + } + var collections = try items.map { try ChartsCollection(from: $0) } + for _ in 0.. Double { + guard let double = try doubleFrom(value, lenientCast: false) else { + throw ChartsError.generalConversion("Unable to cast \(String(describing: value)) to \(Double.self)") + } + return double + } + + public static func doubleFrom(_ value: Any?, lenientCast: Bool = false) throws -> Double? { + guard let value = value else { + return nil + } + if let intValue = value as? Int { + return Double(intValue) + } else if let floatValue = value as? Float { + return Double(floatValue) + } else if let int64Value = value as? Int64 { + return Double(int64Value) + } else if let intValue = value as? Int { + return Double(intValue) + } else if let stringValue = value as? String { + if let doubleValue = Double(stringValue) { + return doubleValue + } + } + if lenientCast { + return nil + } else { + throw ChartsError.generalConversion("Unable to cast \(String(describing: value)) to \(Double.self)") + } + } +} diff --git a/submodules/Charts/Sources/Charts.h b/submodules/Charts/Sources/Charts.h new file mode 100644 index 0000000000..89573b3f16 --- /dev/null +++ b/submodules/Charts/Sources/Charts.h @@ -0,0 +1,19 @@ +// +// StatisticsUI.h +// StatisticsUI +// +// Created by Peter on 8/13/19. +// Copyright © 2019 Telegram Messenger LLP. All rights reserved. +// + +#import + +//! Project version number for StatisticsUI. +FOUNDATION_EXPORT double StatisticsUIVersionNumber; + +//! Project version string for StatisticsUI. +FOUNDATION_EXPORT const unsigned char StatisticsUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift b/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift new file mode 100644 index 0000000000..7f91e50ea5 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/BaseChartController.swift @@ -0,0 +1,166 @@ +// +// BaseChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum BaseConstants { + static let defaultRange: ClosedRange = 0...1 + static let minimumAxisYLabelsDistance: CGFloat = 90 + static let monthDayDateFormatter = DateFormatter.utc(format: "MMM d") + static let timeDateFormatter = DateFormatter.utc(format: "HH:mm") + static let headerFullRangeFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.calendar = Calendar.utc + formatter.dateStyle = .long + return formatter + }() + static let headerMediumRangeFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.dateStyle = .medium + return formatter + }() + static let headerFullZoomedFormatter: DateFormatter = { + let formatter = DateFormatter.utc() + formatter.dateStyle = .full + return formatter + }() + + static let verticalBaseAnchors: [CGFloat] = [8, 5, 2.5, 2, 1] + static let defaultVerticalBaseAnchor: CGFloat = 1 + + static let mainChartLineWidth: CGFloat = 2 + static let previewChartLineWidth: CGFloat = 1 + + static let previewLinesChartOptimizationLevel: CGFloat = 1.5 + static let linesChartOptimizationLevel: CGFloat = 1.0 + static let barsChartOptimizationLevel: CGFloat = 0.75 + + static let defaultRangePresetLength = TimeInterval.day * 60 + + static let chartNumberFormatter: ScalesNumberFormatter = { + let numberFormatter = ScalesNumberFormatter() + numberFormatter.allowsFloats = true + numberFormatter.numberStyle = .decimal + numberFormatter.usesGroupingSeparator = true + numberFormatter.groupingSeparator = " " + numberFormatter.minimumIntegerDigits = 1 + numberFormatter.minimumFractionDigits = 0 + numberFormatter.maximumFractionDigits = 2 + return numberFormatter + }() + + static let detailsNumberFormatter: NumberFormatter = { + let detailsNumberFormatter = NumberFormatter() + detailsNumberFormatter.allowsFloats = false + detailsNumberFormatter.numberStyle = .decimal + detailsNumberFormatter.usesGroupingSeparator = true + detailsNumberFormatter.groupingSeparator = " " + return detailsNumberFormatter + }() +} + +class BaseChartController: ColorModeContainer { + //let performanceRenderer = PerformanceRenderer() + var initialChartsCollection: ChartsCollection + var isZoomed: Bool = false + + var chartTitle: String = "" + + init(chartsCollection: ChartsCollection) { + self.initialChartsCollection = chartsCollection + } + + var mainChartRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + var navigationRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + var cartViewBounds: (() -> CGRect) = { fatalError() } + var chartFrame: (() -> CGRect) = { fatalError() } + + func initializeChart() { + fatalError("Abstract") + } + + func chartInteractionDidBegin(point: CGPoint) { + fatalError("Abstract") + } + + func chartInteractionDidEnd() { + fatalError("Abstract") + } + + func cancelChartInteraction() { + fatalError("Abstract") + } + + func didTapZoomOut() { + fatalError("Abstract") + } + + func updateChartsVisibility(visibility: [Bool], animated: Bool) { + fatalError("Abstract") + } + + var currentHorizontalRange: ClosedRange { + fatalError("Abstract") + } + + var isChartRangePagingEnabled: Bool = false + var minimumSelectedChartRange: CGFloat = 0.05 + var chartRangePagingClosure: ((Bool, CGFloat) -> Void)? // isEnabled, PageSize + func setChartRangePagingEnabled(isEnabled: Bool, minimumSelectionSize: CGFloat) { + isChartRangePagingEnabled = isEnabled + minimumSelectedChartRange = minimumSelectionSize + chartRangePagingClosure?(isChartRangePagingEnabled, minimumSelectedChartRange) + } + + var chartRangeUpdatedClosure: ((ClosedRange, Bool) -> Void)? + var currentChartHorizontalRangeFraction: ClosedRange { + fatalError("Abstract") + } + + func updateChartRange(_ rangeFraction: ClosedRange) { + fatalError("Abstract") + } + + var actualChartVisibility: [Bool] { + fatalError("Abstract") + } + + var actualChartsCollection: ChartsCollection { + fatalError("Abstract") + } + + var drawChartVisibity: Bool { + return true + } + + var drawChartNavigation: Bool { + return true + } + + var setDetailsViewPositionClosure: ((CGFloat) -> Void)? + var setDetailsChartVisibleClosure: ((Bool, Bool) -> Void)? + var setDetailsViewModel: ((ChartDetailsViewModel, Bool) -> Void)? + var getDetailsData: ((Date, @escaping (ChartsCollection?) -> Void) -> Void)? + var setChartTitleClosure: ((String, Bool) -> Void)? + var setBackButtonVisibilityClosure: ((Bool, Bool) -> Void)? + var refreshChartToolsClosure: ((Bool) -> Void)? + + func didTapZoomIn(date: Date) { + fatalError("Abstract") + } + + func apply(colorMode: ColorMode, animated: Bool) { + + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift new file mode 100644 index 0000000000..284be92d3b --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/GeneralChartComponentController.swift @@ -0,0 +1,328 @@ +// +// GeneralChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum GeneralChartComponentConstants { + static let defaultInitialRangeLength = CGFloat(TimeInterval.day * 60) + static let defaultZoomedRangeLength = CGFloat(TimeInterval.day) +} + +class GeneralChartComponentController: ColorModeContainer { + var chartsCollection: ChartsCollection = ChartsCollection.blank + var chartVisibility: [Bool] = [] + var lastChartInteractionPoint: CGPoint = .zero + var isChartInteractionBegun: Bool = false + var isChartInteracting: Bool = false + let isZoomed: Bool + + var colorMode: ColorMode = .day + var totalHorizontalRange: ClosedRange = BaseConstants.defaultRange + var totalVerticalRange: ClosedRange = BaseConstants.defaultRange + var initialHorizontalRange: ClosedRange = BaseConstants.defaultRange + var initialVerticalRange: ClosedRange = BaseConstants.defaultRange + + var cartViewBounds: (() -> CGRect) = { fatalError() } + var chartFrame: (() -> CGRect) = { fatalError() } + + init(isZoomed: Bool) { + self.isZoomed = isZoomed + } + + func initialize(chartsCollection: ChartsCollection, + initialDate: Date, + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + self.chartsCollection = chartsCollection + self.chartVisibility = Array(repeating: true, count: chartsCollection.chartValues.count) + self.totalHorizontalRange = totalHorizontalRange + self.totalVerticalRange = totalVerticalRange + self.initialHorizontalRange = totalHorizontalRange + self.initialVerticalRange = totalVerticalRange + + didLoad() + setupInitialChartRange(initialDate: initialDate) + } + + func didLoad() { + hideDetailsView(animated: false) + } + func willAppear(animated: Bool) { + updateChartRangeTitle(animated: animated) + setupChartRangePaging() + } + func willDisappear(animated: Bool) { + } + + func setupInitialChartRange(initialDate: Date) { + guard let first = chartsCollection.axisValues.first?.timeIntervalSince1970, + let last = chartsCollection.axisValues.last?.timeIntervalSince1970 else { return } + + let rangeStart = CGFloat(first) + let rangeEnd = CGFloat(last) + + if isZoomed { + let initalDate = CGFloat(initialDate.timeIntervalSince1970) + + initialHorizontalRange = max(initalDate, rangeStart)...min(initalDate + GeneralChartComponentConstants.defaultZoomedRangeLength, rangeEnd) + initialVerticalRange = totalVerticalRange + } else { + initialHorizontalRange = max(rangeStart, rangeEnd - GeneralChartComponentConstants.defaultInitialRangeLength)...rangeEnd + initialVerticalRange = totalVerticalRange + } + } + func setupChartRangePaging() { + chartRangePagingClosure?(false, 0.05) + } + + var visibleHorizontalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.current + } + var visibleVerticalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.current + } + var currentHorizontalMainChartRange: ClosedRange { + return currentMainRangeRenderer.horizontalRange.end + } + var currentVerticalMainChartRange: ClosedRange { + return currentMainRangeRenderer.verticalRange.end + } + var currentMainRangeRenderer: BaseChartRenderer { + fatalError("Abstract") + } + + var visiblePreviewHorizontalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.current + } + var visiblePreviewVerticalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.current + } + var currentPreviewHorizontalRange: ClosedRange { + return currentPreviewRangeRenderer.horizontalRange.end + } + var currentPreviewVerticalRange: ClosedRange { + return currentPreviewRangeRenderer.verticalRange.end + } + var currentPreviewRangeRenderer: BaseChartRenderer { + fatalError("Abstract") + } + + var mainChartRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + var previewRenderers: [ChartViewRenderer] { + fatalError("Abstract") + } + + func updateChartsVisibility(visibility: [Bool], animated: Bool) { + self.chartVisibility = visibility + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalMainChartRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalMainChartRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + func chartRangeFractionDidUpdated(_ rangeFraction: ClosedRange) { + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + chartRangeDidUpdated(horizontalRange) + updateChartRangeTitle(animated: true) + } + + func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + hideDetailsView(animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + // MARK: - Details & Interaction + func findClosestDateTo(dateToFind: Date) -> (Date, Int)? { + guard chartsCollection.axisValues.count > 0 else { return nil } + var closestDate = chartsCollection.axisValues[0] + var minIndex = 0 + for (index, date) in chartsCollection.axisValues.enumerated() { + if abs(dateToFind.timeIntervalSince(date)) < abs(dateToFind.timeIntervalSince(closestDate)) { + closestDate = date + minIndex = index + } + } + return (closestDate, minIndex) + } + + func chartInteractionDidBegin(point: CGPoint) { + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + let horizontalRange = currentHorizontalMainChartRange + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + let chartWasInteracting = isChartInteractionBegun + lastChartInteractionPoint = point + isChartInteractionBegun = true + isChartInteracting = true + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + showDetailsView(at: chartValue, detailsViewPosition: detailsViewPosition, dataIndex: minIndex, date: closestDate, animted: chartWasInteracting) + } + + func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + setDetailsViewModel?(chartDetailsViewModel(closestDate: date, pointIndex: dataIndex), animted) + setDetailsChartVisibleClosure?(true, true) + setDetailsViewPositionClosure?(detailsViewPosition) + } + + func chartInteractionDidEnd() { + isChartInteracting = false + } + + func hideDetailsView(animated: Bool) { + isChartInteractionBegun = false + setDetailsChartVisibleClosure?(false, animated) + } + + var visibleDetailsChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = chartVisibility.enumerated().compactMap { args in + args.element ? chartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + var updatePreviewRangeClosure: ((ClosedRange, Bool) -> Void)? + var zoomInOnDateClosure: ((Date) -> Void)? + var setChartTitleClosure: ((String, Bool) -> Void)? + var setDetailsViewPositionClosure: ((CGFloat) -> Void)? + var setDetailsChartVisibleClosure: ((Bool, Bool) -> Void)? + var setDetailsViewModel: ((ChartDetailsViewModel, Bool) -> Void)? + var chartRangePagingClosure: ((Bool, CGFloat) -> Void)? // isEnabled, PageSize + + func apply(colorMode: ColorMode, animated: Bool) { + self.colorMode = colorMode + } + +// MARK: - Helpers + var prevoiusHorizontalStrideInterval: Int = -1 + func updateHorizontalLimitLabels(horizontalScalesRenderer: HorizontalScalesRenderer, + horizontalRange: ClosedRange, + scaleType: ChartScaleType, + forceUpdate: Bool, + animated: Bool) { + let scaleTimeInterval: TimeInterval + if chartsCollection.axisValues.count >= 1 { + scaleTimeInterval = chartsCollection.axisValues[1].timeIntervalSince1970 - chartsCollection.axisValues[0].timeIntervalSince1970 + } else { + scaleTimeInterval = scaleType.timeInterval + } + + let numberOfItems = horizontalRange.distance / CGFloat(scaleTimeInterval) + let maximumNumberOfItems = chartFrame().width / scaleType.minimumAxisXDistance + let tempStride = max(1, Int((numberOfItems / maximumNumberOfItems).rounded(.up))) + var strideInterval = 1 + while strideInterval < tempStride { + strideInterval *= 2 + } + + if forceUpdate || (strideInterval != prevoiusHorizontalStrideInterval && strideInterval > 0) { + var labels: [LinesChartLabel] = [] + for index in stride(from: chartsCollection.axisValues.count - 1, to: -1, by: -strideInterval).reversed() { + let date = chartsCollection.axisValues[index] + labels.append(LinesChartLabel(value: CGFloat(date.timeIntervalSince1970), + text: scaleType.dateFormatter.string(from: date))) + } + prevoiusHorizontalStrideInterval = strideInterval + horizontalScalesRenderer.setup(labels: labels, animated: animated) + } + } + + func verticalLimitsLabels(verticalRange: ClosedRange) -> (ClosedRange, [LinesChartLabel]) { + let ditance = verticalRange.distance + let chartHeight = chartFrame().height + + guard ditance > 0, chartHeight > 0 else { return (BaseConstants.defaultRange, []) } + + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var numberOfOffsetsPerItem = ditance / approximateNumberOfChartValues + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + base = base * multiplier / dividor + + var verticalLabels: [LinesChartLabel] = [] + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let lowerBound = verticalValue + + let numberFormatter = BaseConstants.chartNumberFormatter + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + while verticalValue < verticalRange.upperBound { + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + verticalValue += base + } + let updatedRange = lowerBound...verticalValue + + return (updatedRange, verticalLabels) + } + + func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let values: [ChartDetailsViewModel.Value] = chartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: nil, + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: NSNumber(value: component.values[pointIndex])) ?? "", + color: component.color, + visible: chartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: false, + values: values, + totalValue: nil, + tapAction: { [weak self] in + self?.zoomInOnDateClosure?(closestDate) }) + return viewModel + } + + func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound) + 1) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift new file mode 100644 index 0000000000..60d5069d10 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/BaseLinesChartController.swift @@ -0,0 +1,236 @@ +// +// BaseLinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BaseLinesChartController: BaseChartController { + var chartVisibility: [Bool] + var zoomChartVisibility: [Bool] + var lastChartInteractionPoint: CGPoint = .zero + var isChartInteractionBegun: Bool = false + + var initialChartRange: ClosedRange = BaseConstants.defaultRange + var zoomedChartRange: ClosedRange = BaseConstants.defaultRange + + override init(chartsCollection: ChartsCollection) { + self.chartVisibility = Array(repeating: true, count: chartsCollection.chartValues.count) + self.zoomChartVisibility = [] + super.init(chartsCollection: chartsCollection) + } + + func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + self.initialChartsCollection = chartsCollection + self.isZoomed = isZoomed + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + + updateChartRangeTitle(animated: animated) + } + + func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.lowerBound) + .hour) + let toDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + lastChartInteractionPoint = point + isChartInteractionBegun = true + } + + override func chartInteractionDidEnd() { + + } + + override func cancelChartInteraction() { + isChartInteractionBegun = false + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? zoomChartVisibility : chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return initialChartsCollection + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = actualChartVisibility.enumerated().compactMap { args in + args.element ? initialChartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + + func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let values: [ChartDetailsViewModel.Value] = actualChartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: nil, + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: component.values[pointIndex]), + color: component.color, + visible: actualChartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: false, + values: values, + totalValue: nil, + tapAction: { [weak self] in self?.didTapZoomIn(date: closestDate) }) + return viewModel + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + cancelChartInteraction() + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.initialChartRange = self.currentHorizontalRange + if let startDate = updatedCollection.axisValues.first, + let endDate = updatedCollection.axisValues.last { + self.zoomedChartRange = CGFloat(max(date.timeIntervalSince1970, startDate.timeIntervalSince1970))...CGFloat(min(date.timeIntervalSince1970 + .day - .hour, endDate.timeIntervalSince1970)) + } else { + self.zoomedChartRange = CGFloat(date.timeIntervalSince1970)...CGFloat(date.timeIntervalSince1970 + .day - 1) + } + self.setupChartCollection(chartsCollection: updatedCollection, animated: true, isZoomed: true) + } + }) + } + + func horizontalLimitsLabels(horizontalRange: ClosedRange, + scaleType: ChartScaleType, + prevoiusHorizontalStrideInterval: Int) -> (Int, [LinesChartLabel])? { + let numberOfItems = horizontalRange.distance / CGFloat(scaleType.timeInterval) + let maximumNumberOfItems = chartFrame().width / scaleType.minimumAxisXDistance + let tempStride = max(1, Int((numberOfItems / maximumNumberOfItems).rounded(.up))) + var strideInterval = 1 + while strideInterval < tempStride { + strideInterval *= 2 + } + + if strideInterval != prevoiusHorizontalStrideInterval && strideInterval > 0 { + var labels: [LinesChartLabel] = [] + for index in stride(from: initialChartsCollection.axisValues.count - 1, to: -1, by: -strideInterval).reversed() { + let date = initialChartsCollection.axisValues[index] + labels.append(LinesChartLabel(value: CGFloat(date.timeIntervalSince1970), + text: scaleType.dateFormatter.string(from: date))) + } + return (strideInterval, labels) + } + return nil + } + + func findClosestDateTo(dateToFind: Date) -> (Date, Int)? { + guard initialChartsCollection.axisValues.count > 0 else { return nil } + var closestDate = initialChartsCollection.axisValues[0] + var minIndex = 0 + for (index, date) in initialChartsCollection.axisValues.enumerated() { + if abs(dateToFind.timeIntervalSince(date)) < abs(dateToFind.timeIntervalSince(closestDate)) { + closestDate = date + minIndex = index + } + } + return (closestDate, minIndex) + } + + func verticalLimitsLabels(verticalRange: ClosedRange) -> (ClosedRange, [LinesChartLabel]) { + let ditance = verticalRange.distance + let chartHeight = chartFrame().height + + guard ditance > 0, chartHeight > 0 else { return (BaseConstants.defaultRange, []) } + + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var numberOfOffsetsPerItem = ditance / approximateNumberOfChartValues + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + var base: CGFloat = BaseConstants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + base = base * multiplier / dividor + + var verticalLabels: [LinesChartLabel] = [] + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let lowerBound = verticalValue + + let numberFormatter = BaseConstants.chartNumberFormatter + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + while verticalValue < verticalRange.upperBound { + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + verticalValue += base + } + let updatedRange = lowerBound...verticalValue + + return (updatedRange, verticalLabels) + } +} + +enum ChartScaleType { + case day + case hour + case minutes5 +} + +extension ChartScaleType { + var timeInterval: TimeInterval { + switch self { + case .day: return .day + case .hour: return .hour + case .minutes5: return .minute * 5 + } + } + + var minimumAxisXDistance: CGFloat { + switch self { + case .day: return 50 + case .hour: return 40 + case .minutes5: return 40 + } + } + var dateFormatter: DateFormatter { + switch self { + case .day: return BaseConstants.monthDayDateFormatter + case .hour: return BaseConstants.timeDateFormatter + case .minutes5: return BaseConstants.timeDateFormatter + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift new file mode 100644 index 0000000000..3d52888d72 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/GeneralLinesChartController.swift @@ -0,0 +1,247 @@ +// +// LinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let defaultRange: ClosedRange = 0...1 +} + +class GeneralLinesChartController: BaseLinesChartController { + private let initialChartCollection: ChartsCollection + + private let mainLinesRenderer = LinesChartRenderer() + private let horizontalScalesRenderer = HorizontalScalesRenderer() + private let verticalScalesRenderer = VerticalScalesRenderer() + private let verticalLineRenderer = VerticalLinesRenderer() + private let lineBulletsRenerer = LineBulletsRenerer() + + private let previewLinesRenderer = LinesChartRenderer() + + private var totalVerticalRange: ClosedRange = Constants.defaultRange + private var totalHorizontalRange: ClosedRange = Constants.defaultRange + + private var prevoiusHorizontalStrideInterval: Int = 1 + + private (set) var chartLines: [LinesChartRenderer.LineData] = [] + + override init(chartsCollection: ChartsCollection) { + self.initialChartCollection = chartsCollection + self.mainLinesRenderer.lineWidth = 2 + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + + self.lineBulletsRenerer.isEnabled = false + + super.init(chartsCollection: chartsCollection) + self.zoomChartVisibility = chartVisibility + } + + override func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + super.setupChartCollection(chartsCollection: chartsCollection, animated: animated, isZoomed: isZoomed) + + self.chartLines = chartsCollection.chartValues.map { chart in + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + return LinesChartRenderer.LineData(color: chart.color, points: points) + } + + self.prevoiusHorizontalStrideInterval = -1 + self.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange + self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange + self.lineBulletsRenerer.bullets = self.chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color)} + + let chartRange: ClosedRange + if isZoomed { + chartRange = zoomedChartRange + } else { + chartRange = initialChartRange + } + + self.previewLinesRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + self.previewLinesRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + + self.mainLinesRenderer.setLines(lines: chartLines, animated: animated) + self.previewLinesRenderer.setLines(lines: chartLines, animated: animated) + + updateHorizontalLimists(horizontalRange: chartRange, animated: animated) + updateMainChartHorizontalRange(range: chartRange, animated: animated) + updateVerticalLimitsAndRange(horizontalRange: chartRange, animated: animated) + + self.chartRangeUpdatedClosure?(currentChartHorizontalRangeFraction, animated) + } + + override func initializeChart() { + if let first = initialChartCollection.axisValues.first?.timeIntervalSince1970, + let last = initialChartCollection.axisValues.last?.timeIntervalSince1970 { + initialChartRange = CGFloat(max(first, last - BaseConstants.defaultRangePresetLength))...CGFloat(last) + } + setupChartCollection(chartsCollection: initialChartCollection, animated: false, isZoomed: false) + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [//performanceRenderer, + mainLinesRenderer, + horizontalScalesRenderer, + verticalScalesRenderer, + verticalLineRenderer, + lineBulletsRenerer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [previewLinesRenderer] + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + chartVisibility = visibility + zoomChartVisibility = visibility + for (index, isVisible) in visibility.enumerated() { + mainLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + previewLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + lineBulletsRenerer.setLineVisible(isVisible, at: index, animated: animated) + } + + updateVerticalLimitsAndRange(horizontalRange: currentHorizontalRange, animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + let horizontalRange = mainLinesRenderer.horizontalRange.current + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + let chartInteractionWasBegin = isChartInteractionBegun + + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + super.chartInteractionDidBegin(point: point) + + self.lineBulletsRenerer.bullets = chartLines.compactMap { chart in + return LineBulletsRenerer.Bullet(coordinate: chart.points[minIndex], color: chart.color) + } + self.lineBulletsRenerer.isEnabled = true + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + self.setDetailsViewModel?(chartDetailsViewModel(closestDate: closestDate, pointIndex: minIndex), chartInteractionWasBegin) + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewPositionClosure?(detailsViewPosition) + self.verticalLineRenderer.values = [chartValue] + } + + + override var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + override var currentHorizontalRange: ClosedRange { + return mainLinesRenderer.horizontalRange.end + } + + override func cancelChartInteraction() { + super.cancelChartInteraction() + self.lineBulletsRenerer.isEnabled = false + + self.setDetailsChartVisibleClosure?(false, true) + self.verticalLineRenderer.values = [] + } + + override func didTapZoomOut() { + cancelChartInteraction() + self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false) + } + + var visibleCharts: [LinesChartRenderer.LineData] { + let visibleCharts: [LinesChartRenderer.LineData] = chartVisibility.enumerated().compactMap { args in + args.element ? chartLines[args.offset] : nil + } + return visibleCharts + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + cancelChartInteraction() + + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + + zoomedChartRange = horizontalRange + updateChartRangeTitle(animated: true) + + updateMainChartHorizontalRange(range: horizontalRange, animated: false) + updateHorizontalLimists(horizontalRange: horizontalRange, animated: true) + updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true) + } + + func updateMainChartHorizontalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(horizontalRange: range, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalLineRenderer.setup(horizontalRange: range, animated: animated) + lineBulletsRenerer.setup(horizontalRange: range, animated: animated) + } + + func updateMainChartVerticalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: range, animated: animated) + horizontalScalesRenderer.setup(verticalRange: range, animated: animated) + verticalScalesRenderer.setup(verticalRange: range, animated: animated) + verticalLineRenderer.setup(verticalRange: range, animated: animated) + lineBulletsRenerer.setup(verticalRange: range, animated: animated) + } + + func updateHorizontalLimists(horizontalRange: ClosedRange, animated: Bool) { + if let (stride, labels) = horizontalLimitsLabels(horizontalRange: horizontalRange, + scaleType: isZoomed ? .hour : .day, + prevoiusHorizontalStrideInterval: prevoiusHorizontalStrideInterval) { + self.horizontalScalesRenderer.setup(labels: labels, animated: animated) + self.prevoiusHorizontalStrideInterval = stride + } + } + + func updateVerticalLimitsAndRange(horizontalRange: ClosedRange, animated: Bool) { + if let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: visibleCharts, + calculatingRange: horizontalRange, + addBounds: true) { + + + let (range, labels) = verticalLimitsLabels(verticalRange: verticalRange) + + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + updateMainChartVerticalRange(range: range, animated: animated) + } + verticalScalesRenderer.setVisible(true, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + guard let previewVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: visibleCharts) else { return } + + if previewLinesRenderer.verticalRange.end != previewVerticalRange { + previewLinesRenderer.setup(verticalRange: previewVerticalRange, animated: animated) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift new file mode 100644 index 0000000000..251e76271e --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Lines/TwoAxisLinesChartController.swift @@ -0,0 +1,306 @@ +// +// TwoAxisLinesChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private enum Constants { + static let verticalBaseAnchors: [CGFloat] = [8, 5, 4, 2.5, 2, 1] + static let defaultRange: ClosedRange = 0...1 +} + +class TwoAxisLinesChartController: BaseLinesChartController { + class GraphController { + let mainLinesRenderer = LinesChartRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + let lineBulletsRenerer = LineBulletsRenerer() + let previewLinesRenderer = LinesChartRenderer() + + var chartLines: [LinesChartRenderer.LineData] = [] + + var totalVerticalRange: ClosedRange = Constants.defaultRange + + init() { + self.mainLinesRenderer.lineWidth = 2 + self.previewLinesRenderer.lineWidth = 1 + self.lineBulletsRenerer.isEnabled = false + + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + } + + func updateMainChartVerticalRange(range: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: range, animated: animated) + verticalScalesRenderer.setup(verticalRange: range, animated: animated) + lineBulletsRenerer.setup(verticalRange: range, animated: animated) + } + } + + private var graphControllers: [GraphController] = [] + private let verticalLineRenderer = VerticalLinesRenderer() + private let horizontalScalesRenderer = HorizontalScalesRenderer() + + var totalHorizontalRange: ClosedRange = Constants.defaultRange + + private let initialChartCollection: ChartsCollection + + private var prevoiusHorizontalStrideInterval: Int = 1 + + override init(chartsCollection: ChartsCollection) { + self.initialChartCollection = chartsCollection + graphControllers = chartsCollection.chartValues.map { _ in GraphController() } + + super.init(chartsCollection: chartsCollection) + self.zoomChartVisibility = chartVisibility + } + + override func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) { + super.setupChartCollection(chartsCollection: chartsCollection, animated: animated, isZoomed: isZoomed) + + for (index, controller) in self.graphControllers.enumerated() { + let chart = chartsCollection.chartValues[index] + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + let chartLines = [LinesChartRenderer.LineData(color: chart.color, points: points)] + controller.chartLines = [LinesChartRenderer.LineData(color: chart.color, points: points)] + controller.verticalScalesRenderer.labelsColor = chart.color + controller.totalVerticalRange = LinesChartRenderer.LineData.verticalRange(lines: chartLines) ?? Constants.defaultRange + self.totalHorizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: chartLines) ?? Constants.defaultRange + controller.lineBulletsRenerer.bullets = chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color) } + controller.previewLinesRenderer.setup(horizontalRange: self.totalHorizontalRange, animated: animated) + controller.previewLinesRenderer.setup(verticalRange: controller.totalVerticalRange, animated: animated) + controller.mainLinesRenderer.setLines(lines: chartLines, animated: animated) + controller.previewLinesRenderer.setLines(lines: chartLines, animated: animated) + + controller.verticalScalesRenderer.setHorizontalLinesVisible((index == 0), animated: animated) + controller.verticalScalesRenderer.isRightAligned = (index != 0) + } + + self.prevoiusHorizontalStrideInterval = -1 + + let chartRange: ClosedRange + if isZoomed { + chartRange = zoomedChartRange + } else { + chartRange = initialChartRange + } + + updateHorizontalLimists(horizontalRange: chartRange, animated: animated) + updateMainChartHorizontalRange(range: chartRange, animated: animated) + updateVerticalLimitsAndRange(horizontalRange: chartRange, animated: animated) + + self.chartRangeUpdatedClosure?(currentChartHorizontalRangeFraction, animated) + } + + override func initializeChart() { + if let first = initialChartCollection.axisValues.first?.timeIntervalSince1970, + let last = initialChartCollection.axisValues.last?.timeIntervalSince1970 { + initialChartRange = CGFloat(max(first, last - BaseConstants.defaultRangePresetLength))...CGFloat(last) + } + setupChartCollection(chartsCollection: initialChartCollection, animated: false, isZoomed: false) + } + + override var mainChartRenderers: [ChartViewRenderer] { + return graphControllers.map { $0.mainLinesRenderer } + + graphControllers.flatMap { [$0.verticalScalesRenderer, $0.lineBulletsRenerer] } + + [horizontalScalesRenderer, verticalLineRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return graphControllers.map { $0.previewLinesRenderer } + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + chartVisibility = visibility + zoomChartVisibility = visibility + let firstIndex = visibility.firstIndex(where: { $0 }) + for (index, isVisible) in visibility.enumerated() { + let graph = graphControllers[index] + for graphIndex in graph.chartLines.indices { + graph.mainLinesRenderer.setLineVisible(isVisible, at: graphIndex, animated: animated) + graph.previewLinesRenderer.setLineVisible(isVisible, at: graphIndex, animated: animated) + graph.lineBulletsRenerer.setLineVisible(isVisible, at: graphIndex, animated: animated) + } + graph.verticalScalesRenderer.setVisible(isVisible, animated: animated) + if let firstIndex = firstIndex { + graph.verticalScalesRenderer.setHorizontalLinesVisible(index == firstIndex, animated: animated) + } + } + + updateVerticalLimitsAndRange(horizontalRange: currentHorizontalRange, animated: true) + + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + } + + override func chartInteractionDidBegin(point: CGPoint) { + let horizontalRange = currentHorizontalRange + let chartFrame = self.chartFrame() + guard chartFrame.width > 0 else { return } + + let dateToFind = Date(timeIntervalSince1970: TimeInterval(horizontalRange.distance * point.x + horizontalRange.lowerBound)) + guard let (closestDate, minIndex) = findClosestDateTo(dateToFind: dateToFind) else { return } + + let chartInteractionWasBegin = isChartInteractionBegun + super.chartInteractionDidBegin(point: point) + + for graphController in graphControllers { + graphController.lineBulletsRenerer.bullets = graphController.chartLines.map { chart in + LineBulletsRenerer.Bullet(coordinate: chart.points[minIndex], color: chart.color) + } + graphController.lineBulletsRenerer.isEnabled = true + } + + let chartValue: CGFloat = CGFloat(closestDate.timeIntervalSince1970) + let detailsViewPosition = (chartValue - horizontalRange.lowerBound) / horizontalRange.distance * chartFrame.width + chartFrame.minX + self.setDetailsViewModel?(chartDetailsViewModel(closestDate: closestDate, pointIndex: minIndex), chartInteractionWasBegin) + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewPositionClosure?(detailsViewPosition) + self.verticalLineRenderer.values = [chartValue] + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + let lowerPercent = (currentHorizontalRange.lowerBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + let upperPercent = (currentHorizontalRange.upperBound - totalHorizontalRange.lowerBound) / totalHorizontalRange.distance + return lowerPercent...upperPercent + } + + override var currentHorizontalRange: ClosedRange { + return graphControllers.first?.mainLinesRenderer.horizontalRange.end ?? Constants.defaultRange + } + + override func cancelChartInteraction() { + super.cancelChartInteraction() + for graphController in graphControllers { + graphController.lineBulletsRenerer.isEnabled = false + } + + self.setDetailsChartVisibleClosure?(false, true) + self.verticalLineRenderer.values = [] + } + + override func didTapZoomOut() { + cancelChartInteraction() + self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + cancelChartInteraction() + + let horizontalRange = ClosedRange(uncheckedBounds: + (lower: totalHorizontalRange.lowerBound + rangeFraction.lowerBound * totalHorizontalRange.distance, + upper: totalHorizontalRange.lowerBound + rangeFraction.upperBound * totalHorizontalRange.distance)) + + zoomedChartRange = horizontalRange + updateChartRangeTitle(animated: true) + + updateMainChartHorizontalRange(range: horizontalRange, animated: false) + updateHorizontalLimists(horizontalRange: horizontalRange, animated: true) + updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true) + } + + func updateMainChartHorizontalRange(range: ClosedRange, animated: Bool) { + for controller in graphControllers { + controller.mainLinesRenderer.setup(horizontalRange: range, animated: animated) + controller.verticalScalesRenderer.setup(horizontalRange: range, animated: animated) + controller.lineBulletsRenerer.setup(horizontalRange: range, animated: animated) + } + horizontalScalesRenderer.setup(horizontalRange: range, animated: animated) + verticalLineRenderer.setup(horizontalRange: range, animated: animated) + } + + func updateHorizontalLimists(horizontalRange: ClosedRange, animated: Bool) { + if let (stride, labels) = horizontalLimitsLabels(horizontalRange: horizontalRange, + scaleType: isZoomed ? .hour : .day, + prevoiusHorizontalStrideInterval: prevoiusHorizontalStrideInterval) { + self.horizontalScalesRenderer.setup(labels: labels, animated: animated) + self.prevoiusHorizontalStrideInterval = stride + } + } + + func updateVerticalLimitsAndRange(horizontalRange: ClosedRange, animated: Bool) { + let chartHeight = chartFrame().height + let approximateNumberOfChartValues = (chartHeight / BaseConstants.minimumAxisYLabelsDistance) + + var dividorsAndMultiplers: [(startValue: CGFloat, base: CGFloat, count: Int, maximumNumberOfDecimals: Int)] = graphControllers.enumerated().map { arg in + let (index, controller) = arg + let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: controller.chartLines, + calculatingRange: horizontalRange, + addBounds: true) ?? controller.totalVerticalRange + + var numberOfOffsetsPerItem = verticalRange.distance / approximateNumberOfChartValues + + var multiplier: CGFloat = 1.0 + while numberOfOffsetsPerItem > 10 { + numberOfOffsetsPerItem /= 10 + multiplier *= 10 + } + var dividor: CGFloat = 1.0 + var maximumNumberOfDecimals = 2 + while numberOfOffsetsPerItem < 1 { + numberOfOffsetsPerItem *= 10 + dividor *= 10 + maximumNumberOfDecimals += 1 + } + + let generalBase = Constants.verticalBaseAnchors.first { numberOfOffsetsPerItem > $0 } ?? BaseConstants.defaultVerticalBaseAnchor + let base = generalBase * multiplier / dividor + + var verticalValue = (verticalRange.lowerBound / base).rounded(.down) * base + let startValue = verticalValue + var count = 0 + if chartVisibility[index] { + while verticalValue < verticalRange.upperBound { + count += 1 + verticalValue += base + } + } + return (startValue: startValue, base: base, count: count, maximumNumberOfDecimals: maximumNumberOfDecimals) + } + + let totalCount = dividorsAndMultiplers.map { $0.count }.max() ?? 0 + guard totalCount > 0 else { return } + + let numberFormatter = BaseConstants.chartNumberFormatter + for (index, controller) in graphControllers.enumerated() { + + let (startValue, base, _, maximumNumberOfDecimals) = dividorsAndMultiplers[index] + + let updatedRange = startValue...(startValue + base * CGFloat(totalCount)) + if controller.verticalScalesRenderer.verticalRange.end != updatedRange { + numberFormatter.maximumFractionDigits = maximumNumberOfDecimals + + var verticalLabels: [LinesChartLabel] = [] + for multipler in 0...(totalCount - 1) { + let verticalValue = startValue + base * CGFloat(multipler) + let text: String = numberFormatter.string(from: NSNumber(value: Double(verticalValue))) ?? "" + verticalLabels.append(LinesChartLabel(value: verticalValue, text: text)) + } + + controller.verticalScalesRenderer.setup(verticalLimitsLabels: verticalLabels, animated: animated) + controller.updateMainChartVerticalRange(range: updatedRange, animated: animated) + } + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + + for controller in graphControllers { + controller.verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + controller.lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + controller.verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift new file mode 100644 index 0000000000..d75ba09d91 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentChartComponentController.swift @@ -0,0 +1,195 @@ +// +// PercentChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PercentChartComponentController: GeneralChartComponentController { + let mainPecentChartRenderer: PecentChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + let verticalLineRenderer: VerticalLinesRenderer + let previewPercentChartRenderer: PecentChartRenderer + var percentageData: PecentChartRenderer.PercentageData = .blank + + init(isZoomed: Bool, + mainPecentChartRenderer: PecentChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer, + previewPercentChartRenderer: PecentChartRenderer) { + self.mainPecentChartRenderer = mainPecentChartRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.verticalLineRenderer = verticalLineRenderer + self.previewPercentChartRenderer = previewPercentChartRenderer + + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let components = chartsCollection.chartValues.map { PecentChartRenderer.PercentageData.Component(color: $0.color, + values: $0.values.map { CGFloat($0) }) } + self.percentageData = PecentChartRenderer.PercentageData(locations: chartsCollection.axisValues.map { CGFloat($0.timeIntervalSince1970) }, + components: components) + let totalHorizontalRange = PecentChartRenderer.PercentageData.horizontalRange(data: self.percentageData) ?? BaseConstants.defaultRange + let totalVerticalRange = BaseConstants.defaultRange + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + + mainPecentChartRenderer.percentageData = self.percentageData + previewPercentChartRenderer.percentageData = self.percentageData + + let axisValues: [CGFloat] = [0, 25, 50, 75, 100] + let labels: [LinesChartLabel] = axisValues.map { value in + return LinesChartLabel(value: value / 100, text: BaseConstants.detailsNumberFormatter.string(from: NSNumber(value: Double(value))) ?? "") + } + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: false) + + setupMainChart(horizontalRange: initialHorizontalRange, animated: false) + setupMainChart(verticalRange: initialVerticalRange, animated: false) + previewPercentChartRenderer.setup(verticalRange: totalVerticalRange, animated: false) + previewPercentChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: false) + updateHorizontalLimitLabels(animated: false) + } + + override func willAppear(animated: Bool) { + previewPercentChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewPercentChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setConponentsVisible(visible: true, animated: true) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + + super.willAppear(animated: animated) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + + initialHorizontalRange = updatedRange + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: initialHorizontalRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: false, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainPecentChartRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + verticalLineRenderer.setVisible(visible, animated: animated) + previewPercentChartRenderer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainPecentChartRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalLineRenderer.setup(horizontalRange: horizontalRange, animated: animated) + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainPecentChartRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalLineRenderer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainPecentChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewPercentChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + verticalScalesRenderer.setVisible(visibility.contains(true), animated: animated) + } + + override func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + let visibleValues = visibleDetailsChartValues + + let total = visibleValues.map { $0.values[pointIndex] }.reduce(0, +) + + let values: [ChartDetailsViewModel.Value] = chartsCollection.chartValues.enumerated().map { arg in + let (index, component) = arg + return ChartDetailsViewModel.Value(prefix: PercentConstants.percentValueFormatter.string(from: component.values[pointIndex] / total * 100), + title: component.name, + value: BaseConstants.detailsNumberFormatter.string(from: component.values[pointIndex]), + color: component.color, + visible: chartVisibility[index]) + } + let dateString: String + if isZoomed { + dateString = BaseConstants.timeDateFormatter.string(from: closestDate) + } else { + dateString = BaseConstants.headerMediumRangeFormatter.string(from: closestDate) + } + let viewModel = ChartDetailsViewModel(title: dateString, + showArrow: !self.isZoomed, + showPrefixes: true, + values: values, + totalValue: nil, + tapAction: { [weak self] in + self?.hideDetailsView(animated: true) + self?.zoomInOnDateClosure?(closestDate) }) + return viewModel + } + + var currentlyVisiblePercentageData: PecentChartRenderer.PercentageData { + var currentPercentageData = percentageData + currentPercentageData.components = chartVisibility.enumerated().compactMap { $0.element ? currentPercentageData.components[$0.offset] : nil } + return currentPercentageData + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainPecentChartRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewPercentChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + super.showDetailsView(at: chartPosition, detailsViewPosition: detailsViewPosition, dataIndex: dataIndex, date: date, animted: animted) + verticalLineRenderer.values = [chartPosition] + verticalLineRenderer.isEnabled = true + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + verticalLineRenderer.values = [] + verticalLineRenderer.isEnabled = false + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.barChartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.barChartStrongLinesColor + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift new file mode 100644 index 0000000000..484d8a2f11 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PercentPieChartController.swift @@ -0,0 +1,281 @@ +// +// PercentPieChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +enum PercentConstants { + static let percentValueFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.positiveSuffix = "%" + return formatter + }() +} + +private enum Constants { + static let zoomedRange = 7 +} + +class PercentPieChartController: BaseChartController { + let percentController: PercentChartComponentController + let pieController: PieChartComponentController + let transitionRenderer: PercentPieAnimationRenderer + + override init(chartsCollection: ChartsCollection) { + transitionRenderer = PercentPieAnimationRenderer() + percentController = PercentChartComponentController(isZoomed: false, + mainPecentChartRenderer: PecentChartRenderer(), + horizontalScalesRenderer: HorizontalScalesRenderer(), + verticalScalesRenderer: VerticalScalesRenderer(), + verticalLineRenderer: VerticalLinesRenderer(), + previewPercentChartRenderer: PecentChartRenderer()) + pieController = PieChartComponentController(isZoomed: true, + pieChartRenderer: PieChartRenderer(), + previewBarChartRenderer: BarChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [percentController, pieController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + transitionRenderer.isEnabled = false + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [percentController.mainPecentChartRenderer, + transitionRenderer, + percentController.horizontalScalesRenderer, + percentController.verticalScalesRenderer, + percentController.verticalLineRenderer, + pieController.pieChartRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [percentController.previewPercentChartRenderer, + pieController.previewBarChartRenderer] + } + + override func initializeChart() { + percentController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: percentController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = pieController.initialHorizontalRange + + pieController.updateChartsVisibility(visibility: percentController.chartVisibility, animated: false) + pieController.pieChartRenderer.setup(horizontalRange: percentController.currentHorizontalMainChartRange, animated: false) + pieController.previewBarChartRenderer.setup(horizontalRange: percentController.currentPreviewHorizontalRange, animated: false) + pieController.pieChartRenderer.setVisible(false, animated: false) + pieController.previewBarChartRenderer.setVisible(true, animated: false) + + pieController.willAppear(animated: animated) + percentController.willDisappear(animated: animated) + + pieController.pieChartRenderer.drawPie = false + percentController.mainPecentChartRenderer.isEnabled = false + + setupTransitionRenderer() + + percentController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + percentController.previewPercentChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + percentController.setConponentsVisible(visible: false, animated: animated) + + transitionRenderer.animate(fromDataToPie: true, animated: animated) { [weak self] in + self?.pieController.pieChartRenderer.drawPie = true + self?.percentController.mainPecentChartRenderer.isEnabled = true + } + } else { + if !pieController.chartsCollection.isBlank { + let fromHorizontalRange = pieController.currentHorizontalMainChartRange + let toHorizontalRange = percentController.initialHorizontalRange + + pieController.pieChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + pieController.previewBarChartRenderer.setup(horizontalRange: toHorizontalRange, animated: animated) + pieController.pieChartRenderer.setVisible(false, animated: animated) + pieController.previewBarChartRenderer.setVisible(false, animated: animated) + + percentController.updateChartsVisibility(visibility: pieController.chartVisibility, animated: false) + percentController.setupMainChart(horizontalRange: fromHorizontalRange, animated: false) + percentController.previewPercentChartRenderer.setup(horizontalRange: fromHorizontalRange, animated: false) + percentController.setConponentsVisible(visible: false, animated: false) + } + + percentController.willAppear(animated: animated) + pieController.willDisappear(animated: animated) + + if animated { + pieController.pieChartRenderer.drawPie = false + percentController.mainPecentChartRenderer.isEnabled = false + + setupTransitionRenderer() + + transitionRenderer.animate(fromDataToPie: false, animated: true) { + self.pieController.pieChartRenderer.drawPie = true + self.percentController.mainPecentChartRenderer.isEnabled = true + } + } + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + } + + func setupTransitionRenderer() { + transitionRenderer.setup(verticalRange: percentController.currentVerticalMainChartRange, animated: false) + transitionRenderer.setup(horizontalRange: percentController.currentHorizontalMainChartRange, animated: false) + transitionRenderer.visiblePieComponents = pieController.visiblePieDataWithCurrentPreviewRange + transitionRenderer.visiblePercentageData = percentController.currentlyVisiblePercentageData + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + pieController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + percentController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? pieController.chartVisibility : percentController.chartVisibility + let collection = isZoomed ? pieController.chartsCollection : percentController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? pieController.chartVisibility : percentController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? pieController.chartsCollection : percentController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + pieController.chartInteractionDidBegin(point: point) + } else { + percentController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + pieController.chartInteractionDidEnd() + } else { + percentController.chartInteractionDidEnd() + } + } + + override var drawChartVisibity: Bool { + return true + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return pieController.currentChartHorizontalRangeFraction + } else { + return percentController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return pieController.hideDetailsView(animated: true) + } else { + return percentController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + cancelChartInteraction() + let currentCollection = percentController.chartsCollection + let range: Int = Constants.zoomedRange + guard let (foundDate, index) = percentController.findClosestDateTo(dateToFind: date) else { return } + var lowIndex = max(0, index - range / 2) + var highIndex = min(currentCollection.axisValues.count - 1, index + range / 2) + if lowIndex == 0 { + highIndex = lowIndex + (range - 1) + } else if highIndex == currentCollection.axisValues.count - 1 { + lowIndex = highIndex - (range - 1) + } + + let newValues = currentCollection.chartValues.map { chart in + return ChartsCollection.Chart(color: chart.color, + name: chart.name, + values: Array(chart.values[(lowIndex...highIndex)])) + } + let newCollection = ChartsCollection(axisValues: Array(currentCollection.axisValues[(lowIndex...highIndex)]), + chartValues: newValues) + let selectedRange = CGFloat(foundDate.timeIntervalSince1970 - .day)...CGFloat(foundDate.timeIntervalSince1970) + pieController.initialize(chartsCollection: newCollection, initialDate: date, totalHorizontalRange: 0...1, totalVerticalRange: 0...1) + pieController.initialHorizontalRange = selectedRange + + switchToChart(chartsCollection: newCollection, isZoomed: true, animated: true) + } + + override func didTapZoomOut() { + self.pieController.deselectSegment(completion: { [weak self] in + guard let self = self else { return } + self.switchToChart(chartsCollection: self.percentController.chartsCollection, isZoomed: false, animated: true) + }) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return pieController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return percentController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + pieController.apply(colorMode: colorMode, animated: animated) + percentController.apply(colorMode: colorMode, animated: animated) + transitionRenderer.backgroundColor = colorMode.chartBackgroundColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift new file mode 100644 index 0000000000..68c3541912 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Percent And Pie/PieChartComponentController.swift @@ -0,0 +1,198 @@ +// +// PieChartComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PieChartComponentController: GeneralChartComponentController { + let pieChartRenderer: PieChartRenderer + let previewBarChartRenderer: BarChartRenderer + var barWidth: CGFloat = 1 + + var chartBars: BarChartRenderer.BarsData = .blank + + init(isZoomed: Bool, + pieChartRenderer: PieChartRenderer, + previewBarChartRenderer: BarChartRenderer) { + self.pieChartRenderer = pieChartRenderer + self.previewBarChartRenderer = previewBarChartRenderer + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let (width, chartBars, totalHorizontalRange, _) = BarChartRenderer.BarsData.initialComponents(chartsCollection: chartsCollection) + self.barWidth = width + self.chartBars = chartBars + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: BaseConstants.defaultRange) + + self.previewBarChartRenderer.bars = chartBars + self.previewBarChartRenderer.fillToTop = true + + pieChartRenderer.valuesFormatter = PercentConstants.percentValueFormatter + pieChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: false) + previewBarChartRenderer.setup(verticalRange: initialVerticalRange, animated: false) + previewBarChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: false) + + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: false) + pieChartRenderer.selectSegmentAt(at: nil, animated: false) + } + + private var pieDataWithCurrentPreviewRange: [PieChartRenderer.PieComponent] { + let range = currentHorizontalMainChartRange + var pieComponents = chartsCollection.chartValues.map { PieChartRenderer.PieComponent(color: $0.color, + value: 0) } + guard var valueIndex = chartsCollection.axisValues.firstIndex(where: { CGFloat($0.timeIntervalSince1970) > (range.lowerBound + 1)}) else { + return pieComponents + } + var count = 0 + while valueIndex < chartsCollection.axisValues.count, CGFloat(chartsCollection.axisValues[valueIndex].timeIntervalSince1970) <= range.upperBound { + count += 1 + for pieIndex in pieComponents.indices { + pieComponents[pieIndex].value += CGFloat(chartsCollection.chartValues[pieIndex].values[valueIndex]) + } + valueIndex += 1 + } + return pieComponents + } + + var visiblePieDataWithCurrentPreviewRange: [PieChartRenderer.PieComponent] { + let currentData = pieDataWithCurrentPreviewRange + return chartVisibility.enumerated().compactMap { $0.element ? currentData[$0.offset] : nil } + } + + override func willAppear(animated: Bool) { + pieChartRenderer.setup(horizontalRange: initialHorizontalRange, animated: animated) + pieChartRenderer.setVisible(true, animated: animated) + + previewBarChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewBarChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + previewBarChartRenderer.setVisible(true, animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: false) + + super.willAppear(animated: animated) + } + + override func setupChartRangePaging() { + let valuesCount = chartsCollection.axisValues.count + guard valuesCount > 0 else { return } + chartRangePagingClosure?(true, 1.0 / CGFloat(valuesCount)) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + if isChartInteractionBegun { + chartInteractionDidBegin(point: lastChartInteractionPoint) + } + initialHorizontalRange = updatedRange + + setupMainChart(horizontalRange: updatedRange, animated: true) + updateSelectedDataLabelIfNeeded() + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + pieChartRenderer.setup(horizontalRange: horizontalRange, animated: animated) + pieChartRenderer.updatePercentageData(pieDataWithCurrentPreviewRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + pieChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewBarChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + if let segment = pieChartRenderer.selectedSegment { + if !visibility[segment] { + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + } + } + updateSelectedDataLabelIfNeeded() + } + + func deselectSegment(completion: @escaping () -> Void) { + if pieChartRenderer.hasSelectedSegments { + hideDetailsView(animated: true) + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration / 2) { + completion() + } + } else { + completion() + } + } + + func updateSelectedDataLabelIfNeeded() { + if let segment = pieChartRenderer.selectedSegment { + self.setDetailsChartVisibleClosure?(true, true) + self.setDetailsViewModel?(chartDetailsViewModel(segmentInde: segment), false) + self.setDetailsViewPositionClosure?(chartFrame().width / 4) + } else { + self.setDetailsChartVisibleClosure?(false, true) + } + } + + func chartDetailsViewModel(segmentInde: Int) -> ChartDetailsViewModel { + let pieItem = pieDataWithCurrentPreviewRange[segmentInde] + let title = chartsCollection.chartValues[segmentInde].name + let valueString = BaseConstants.detailsNumberFormatter.string(from: pieItem.value) + let viewModel = ChartDetailsViewModel(title: "", + showArrow: false, + showPrefixes: false, + values: [ChartDetailsViewModel.Value(prefix: nil, + title: title, + value: valueString, + color: pieItem.color, + visible: true)], + totalValue: nil, + tapAction: nil) + return viewModel + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return pieChartRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewBarChartRenderer + } + + var lastInteractionPoint: CGPoint = .zero + override func chartInteractionDidBegin(point: CGPoint) { + lastInteractionPoint = point + } + + override func chartInteractionDidEnd() { + if let segment = pieChartRenderer.selectedItemIndex(at: lastInteractionPoint) { + if pieChartRenderer.selectedSegment == segment { + pieChartRenderer.selectSegmentAt(at: nil, animated: true) + } else { + pieChartRenderer.selectSegmentAt(at: segment, animated: true) + } + updateSelectedDataLabelIfNeeded() + } + } + + override func hideDetailsView(animated: Bool) { + pieChartRenderer.selectSegmentAt(at: nil, animated: animated) + updateSelectedDataLabelIfNeeded() + } + + override func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound) + .day + 1) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift new file mode 100644 index 0000000000..2e1894465b --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/BarsComponentController.swift @@ -0,0 +1,226 @@ +// +// BarsComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BarsComponentController: GeneralChartComponentController { + let mainBarsRenderer: BarChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + + let previewBarsChartRenderer: BarChartRenderer + private(set) var barsWidth: CGFloat = 1 + + private (set) var chartBars: BarChartRenderer.BarsData = .blank + + init(isZoomed: Bool, + mainBarsRenderer: BarChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer) { + self.mainBarsRenderer = mainBarsRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.previewBarsChartRenderer = previewBarsChartRenderer + + self.mainBarsRenderer.optimizationLevel = BaseConstants.barsChartOptimizationLevel + self.previewBarsChartRenderer.optimizationLevel = BaseConstants.barsChartOptimizationLevel + + super.init(isZoomed: isZoomed) + } + + override func initialize(chartsCollection: ChartsCollection, initialDate: Date, totalHorizontalRange _: ClosedRange, totalVerticalRange _: ClosedRange) { + let (width, chartBars, totalHorizontalRange, totalVerticalRange) = BarChartRenderer.BarsData.initialComponents(chartsCollection: chartsCollection) + self.chartBars = chartBars + self.barsWidth = width + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + } + + override func setupInitialChartRange(initialDate: Date) { + guard let first = chartsCollection.axisValues.first?.timeIntervalSince1970, + let last = chartsCollection.axisValues.last?.timeIntervalSince1970 else { return } + + let rangeStart = CGFloat(first) + let rangeEnd = CGFloat(last) + + if isZoomed { + let initalDate = CGFloat(initialDate.timeIntervalSince1970) + + initialHorizontalRange = max(initalDate - barsWidth, rangeStart)...min(initalDate + GeneralChartComponentConstants.defaultZoomedRangeLength - barsWidth, rangeEnd) + initialVerticalRange = totalVerticalRange + } else { + super.setupInitialChartRange(initialDate: initialDate) + } + } + + + override func willAppear(animated: Bool) { + mainBarsRenderer.bars = self.chartBars + previewBarsChartRenderer.bars = self.chartBars + + previewBarsChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewBarsChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updateChartVerticalRanges(horizontalRange: initialHorizontalRange, animated: animated) + + super.willAppear(animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + setConponentsVisible(visible: true, animated: animated) + updateHorizontalLimitLabels(animated: animated, forceUpdate: true) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + if !isZoomed { + initialHorizontalRange = updatedRange + } + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true, forceUpdate: false) + updateChartVerticalRanges(horizontalRange: updatedRange, animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool, forceUpdate: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: currentHorizontalMainChartRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: forceUpdate, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainBarsRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + previewBarsChartRenderer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainBarsRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + } + + var visibleBars: BarChartRenderer.BarsData { + let visibleComponents: [BarChartRenderer.BarsData.Component] = chartVisibility.enumerated().compactMap { args in + args.element ? chartBars.components[args.offset] : nil + } + return BarChartRenderer.BarsData(barWidth: chartBars.barWidth, + locations: chartBars.locations, + components: visibleComponents) + } + + func updateChartVerticalRanges(horizontalRange: ClosedRange, animated: Bool) { + if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars, + calculatingRange: horizontalRange, + addBounds: true) { + let (range, labels) = verticalLimitsLabels(verticalRange: range) + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + } + verticalScalesRenderer.setVisible(true, animated: animated) + + setupMainChart(verticalRange: range, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + if let range = BarChartRenderer.BarsData.verticalRange(bars: visibleBars) { + previewBarsChartRenderer.setup(verticalRange: range, animated: animated) + } + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainBarsRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainBarsRenderer.setComponentVisible(isVisible, at: index, animated: animated) + previewBarsChartRenderer.setComponentVisible(isVisible, at: index, animated: animated) + } + updateChartVerticalRanges(horizontalRange: currentHorizontalMainChartRange, animated: true) + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibleCharts: [ChartsCollection.Chart] = chartVisibility.enumerated().compactMap { args in + args.element ? chartsCollection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override func chartDetailsViewModel(closestDate: Date, pointIndex: Int) -> ChartDetailsViewModel { + var viewModel = super.chartDetailsViewModel(closestDate: closestDate, pointIndex: pointIndex) + let visibleChartValues = self.visibleChartValues + let totalSumm: CGFloat = visibleChartValues.map { CGFloat($0.values[pointIndex]) }.reduce(0, +) + + viewModel.totalValue = ChartDetailsViewModel.Value(prefix: nil, + title: "Total", + value: BaseConstants.detailsNumberFormatter.string(from: totalSumm), + color: .white, + visible: visibleChartValues.count > 1) + return viewModel + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainBarsRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewBarsChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + let rangeWithOffset = detailsViewPosition - barsWidth / currentHorizontalMainChartRange.distance * chartFrame().width / 2 + super.showDetailsView(at: chartPosition, detailsViewPosition: rangeWithOffset, dataIndex: dataIndex, date: date, animted: animted) + mainBarsRenderer.setSelectedIndex(dataIndex, animated: true) + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + mainBarsRenderer.setSelectedIndex(nil, animated: animated) + } + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.barChartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.barChartStrongLinesColor + mainBarsRenderer.update(backgroundColor: colorMode.chartBackgroundColor, animated: false) + previewBarsChartRenderer.update(backgroundColor: colorMode.chartBackgroundColor, animated: false) + } + + override func updateChartRangeTitle(animated: Bool) { + let fromDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.lowerBound + barsWidth)) + let toDate = Date(timeIntervalSince1970: TimeInterval(currentHorizontalMainChartRange.upperBound)) + if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) { + let stirng = BaseConstants.headerFullZoomedFormatter.string(from: fromDate) + self.setChartTitleClosure?(stirng, animated) + } else { + let stirng = "\(BaseConstants.headerMediumRangeFormatter.string(from: fromDate)) - \(BaseConstants.headerMediumRangeFormatter.string(from: toDate))" + self.setChartTitleClosure?(stirng, animated) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift new file mode 100644 index 0000000000..ae83803bb1 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/DailyBarsChartController.swift @@ -0,0 +1,249 @@ +// +// DailyBarsChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class DailyBarsChartController: BaseChartController { + let barsController: BarsComponentController + let linesController: LinesComponentController + + override init(chartsCollection: ChartsCollection) { + let horizontalScalesRenderer = HorizontalScalesRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + barsController = BarsComponentController(isZoomed: false, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + linesController = LinesComponentController(isZoomed: true, + userLinesTransitionAnimation: false, + mainLinesRenderer: LinesChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer(), + lineBulletsRenerer: LineBulletsRenerer(), + previewLinesChartRenderer: LinesChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [barsController, linesController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [barsController.mainBarsRenderer, + linesController.mainLinesRenderer, + barsController.horizontalScalesRenderer, + barsController.verticalScalesRenderer, + linesController.verticalLineRenderer, + linesController.lineBulletsRenerer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [barsController.previewBarsChartRenderer, + linesController.previewLinesChartRenderer] + } + + override func initializeChart() { + barsController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = linesController.initialHorizontalRange + let destinationHorizontalRange = (toHorizontalRange.lowerBound - barsController.barsWidth)...(toHorizontalRange.upperBound - barsController.barsWidth) + let initialChartVerticalRange = lineProportionAnimationRange() + + linesController.mainLinesRenderer.setup(horizontalRange: barsController.currentHorizontalMainChartRange, animated: false) + linesController.previewLinesChartRenderer.setup(horizontalRange: barsController.currentPreviewHorizontalRange, animated: false) + linesController.mainLinesRenderer.setup(verticalRange: initialChartVerticalRange, animated: false) + linesController.previewLinesChartRenderer.setup(verticalRange: initialChartVerticalRange, animated: false) + linesController.mainLinesRenderer.setVisible(false, animated: false) + linesController.previewLinesChartRenderer.setVisible(false, animated: false) + + barsController.setupMainChart(horizontalRange: destinationHorizontalRange, animated: animated) + barsController.previewBarsChartRenderer.setup(horizontalRange: linesController.totalHorizontalRange, animated: animated) + barsController.mainBarsRenderer.setVisible(false, animated: animated) + barsController.previewBarsChartRenderer.setVisible(false, animated: animated) + + linesController.willAppear(animated: animated) + barsController.willDisappear(animated: animated) + + linesController.updateChartsVisibility(visibility: linesController.chartLines.map { _ in true }, animated: false) + } else { + if !linesController.chartsCollection.isBlank { + barsController.hideDetailsView(animated: false) + let visibleVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: barsController.visibleBars, + calculatingRange: barsController.initialHorizontalRange) ?? BaseConstants.defaultRange + barsController.mainBarsRenderer.setup(verticalRange: visibleVerticalRange, animated: false) + + let toHorizontalRange = barsController.initialHorizontalRange + let destinationChartVerticalRange = lineProportionAnimationRange() + + linesController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + linesController.mainLinesRenderer.setup(verticalRange: destinationChartVerticalRange, animated: animated) + linesController.previewLinesChartRenderer.setup(verticalRange: destinationChartVerticalRange, animated: animated) + linesController.previewLinesChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) + linesController.mainLinesRenderer.setVisible(false, animated: animated) + linesController.previewLinesChartRenderer.setVisible(false, animated: animated) + } + + barsController.willAppear(animated: animated) + linesController.willDisappear(animated: animated) + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + self.refreshChartToolsClosure?(animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + linesController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + barsController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? linesController.chartVisibility : barsController.chartVisibility + let collection = isZoomed ? linesController.chartsCollection : barsController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? linesController.chartVisibility : barsController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? linesController.chartsCollection : barsController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + linesController.chartInteractionDidBegin(point: point) + } else { + barsController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + linesController.chartInteractionDidEnd() + } else { + barsController.chartInteractionDidEnd() + } + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return linesController.currentChartHorizontalRangeFraction + } else { + return barsController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return linesController.hideDetailsView(animated: true) + } else { + return barsController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + if isZoomed { + return linesController.hideDetailsView(animated: true) + } + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.linesController.initialize(chartsCollection: updatedCollection, + initialDate: date, + totalHorizontalRange: 0...1, + totalVerticalRange: 0...1) + self.switchToChart(chartsCollection: updatedCollection, isZoomed: true, animated: true) + } + }) + } + + func lineProportionAnimationRange() -> ClosedRange { + let visibleLines = self.barsController.chartVisibility.enumerated().compactMap { $0.element ? self.linesController.chartLines[$0.offset] : nil } + let linesRange = LinesChartRenderer.LineData.verticalRange(lines: visibleLines) ?? BaseConstants.defaultRange + let barsRange = BarChartRenderer.BarsData.verticalRange(bars: self.barsController.visibleBars, + calculatingRange: self.linesController.totalHorizontalRange) ?? BaseConstants.defaultRange + let range = 0...(linesRange.upperBound / barsRange.distance * self.barsController.currentVerticalMainChartRange.distance) + return range + } + + override func didTapZoomOut() { + cancelChartInteraction() + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return linesController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return barsController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + linesController.apply(colorMode: colorMode, animated: animated) + barsController.apply(colorMode: colorMode, animated: animated) + } + + override var drawChartVisibity: Bool { + return isZoomed + } +} + +//TODO: Убрать Performance полоски сверзу чартов (Не забыть) +//TODO: Добавить ховеры на кнопки diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift new file mode 100644 index 0000000000..fc39a5f4c6 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/LinesComponentController.swift @@ -0,0 +1,210 @@ +// +// LinesComponentController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/14/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LinesComponentController: GeneralChartComponentController { + let mainLinesRenderer: LinesChartRenderer + let horizontalScalesRenderer: HorizontalScalesRenderer + let verticalScalesRenderer: VerticalScalesRenderer + let verticalLineRenderer: VerticalLinesRenderer + let lineBulletsRenerer: LineBulletsRenerer + + let previewLinesChartRenderer: LinesChartRenderer + + private let zoomedLinesRenderer = LinesChartRenderer() + private let zoomedPreviewLinesRenderer = LinesChartRenderer() + + private let userLinesTransitionAnimation: Bool + + private(set) var chartLines: [LinesChartRenderer.LineData] = [] + + init(isZoomed: Bool, + userLinesTransitionAnimation: Bool, + mainLinesRenderer: LinesChartRenderer, + horizontalScalesRenderer: HorizontalScalesRenderer, + verticalScalesRenderer: VerticalScalesRenderer, + verticalLineRenderer: VerticalLinesRenderer, + lineBulletsRenerer: LineBulletsRenerer, + previewLinesChartRenderer: LinesChartRenderer) { + self.mainLinesRenderer = mainLinesRenderer + self.horizontalScalesRenderer = horizontalScalesRenderer + self.verticalScalesRenderer = verticalScalesRenderer + self.verticalLineRenderer = verticalLineRenderer + self.lineBulletsRenerer = lineBulletsRenerer + self.previewLinesChartRenderer = previewLinesChartRenderer + self.userLinesTransitionAnimation = userLinesTransitionAnimation + + super.init(isZoomed: isZoomed) + + self.mainLinesRenderer.lineWidth = BaseConstants.mainChartLineWidth + self.mainLinesRenderer.optimizationLevel = BaseConstants.linesChartOptimizationLevel + self.previewLinesChartRenderer.lineWidth = BaseConstants.previewChartLineWidth + self.previewLinesChartRenderer.optimizationLevel = BaseConstants.previewLinesChartOptimizationLevel + + self.lineBulletsRenerer.isEnabled = false + } + + override func initialize(chartsCollection: ChartsCollection, + initialDate: Date, + totalHorizontalRange _: ClosedRange, + totalVerticalRange _: ClosedRange) { + let (chartLines, totalHorizontalRange, totalVerticalRange) = LinesChartRenderer.LineData.initialComponents(chartsCollection: chartsCollection) + self.chartLines = chartLines + + self.lineBulletsRenerer.bullets = self.chartLines.map { LineBulletsRenerer.Bullet(coordinate: $0.points.first ?? .zero, + color: $0.color)} + + super.initialize(chartsCollection: chartsCollection, + initialDate: initialDate, + totalHorizontalRange: totalHorizontalRange, + totalVerticalRange: totalVerticalRange) + + self.mainLinesRenderer.setup(verticalRange: totalVerticalRange, animated: true) + } + + override func willAppear(animated: Bool) { + mainLinesRenderer.setLines(lines: self.chartLines, animated: animated && userLinesTransitionAnimation) + previewLinesChartRenderer.setLines(lines: self.chartLines, animated: animated && userLinesTransitionAnimation) + + previewLinesChartRenderer.setup(verticalRange: totalVerticalRange, animated: animated) + previewLinesChartRenderer.setup(horizontalRange: totalHorizontalRange, animated: animated) + + setupMainChart(verticalRange: initialVerticalRange, animated: animated) + setupMainChart(horizontalRange: initialHorizontalRange, animated: animated) + + updateChartVerticalRanges(horizontalRange: initialHorizontalRange, animated: animated) + + super.willAppear(animated: animated) + + updatePreviewRangeClosure?(currentChartHorizontalRangeFraction, animated) + setConponentsVisible(visible: true, animated: animated) + updateHorizontalLimitLabels(animated: animated, forceUpdate: true) + } + + override func chartRangeDidUpdated(_ updatedRange: ClosedRange) { + super.chartRangeDidUpdated(updatedRange) + if !isZoomed { + initialHorizontalRange = updatedRange + } + setupMainChart(horizontalRange: updatedRange, animated: false) + updateHorizontalLimitLabels(animated: true, forceUpdate: false) + updateChartVerticalRanges(horizontalRange: updatedRange, animated: true) + } + + func updateHorizontalLimitLabels(animated: Bool, forceUpdate: Bool) { + updateHorizontalLimitLabels(horizontalScalesRenderer: horizontalScalesRenderer, + horizontalRange: currentHorizontalMainChartRange, + scaleType: isZoomed ? .hour : .day, + forceUpdate: forceUpdate, + animated: animated) + } + + func prepareAppearanceAnimation(horizontalRnage: ClosedRange) { + setupMainChart(horizontalRange: horizontalRnage, animated: false) + setConponentsVisible(visible: false, animated: false) + } + + func setConponentsVisible(visible: Bool, animated: Bool) { + mainLinesRenderer.setVisible(visible, animated: animated) + horizontalScalesRenderer.setVisible(visible, animated: animated) + verticalScalesRenderer.setVisible(visible, animated: animated) + verticalLineRenderer.setVisible(visible, animated: animated) + previewLinesChartRenderer.setVisible(visible, animated: animated) + lineBulletsRenerer.setVisible(visible, animated: animated) + } + + func setupMainChart(horizontalRange: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + horizontalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalScalesRenderer.setup(horizontalRange: horizontalRange, animated: animated) + verticalLineRenderer.setup(horizontalRange: horizontalRange, animated: animated) + lineBulletsRenerer.setup(horizontalRange: horizontalRange, animated: animated) + } + + var visibleLines: [LinesChartRenderer.LineData] { + return chartVisibility.enumerated().compactMap { $0.element ? chartLines[$0.offset] : nil } + } + + func updateChartVerticalRanges(horizontalRange: ClosedRange, animated: Bool) { + if let range = LinesChartRenderer.LineData.verticalRange(lines: visibleLines, + calculatingRange: horizontalRange, + addBounds: true) { + let (range, labels) = verticalLimitsLabels(verticalRange: range) + if verticalScalesRenderer.verticalRange.end != range { + verticalScalesRenderer.setup(verticalLimitsLabels: labels, animated: animated) + } + + setupMainChart(verticalRange: range, animated: animated) + verticalScalesRenderer.setVisible(true, animated: animated) + } else { + verticalScalesRenderer.setVisible(false, animated: animated) + } + + if let range = LinesChartRenderer.LineData.verticalRange(lines: visibleLines) { + previewLinesChartRenderer.setup(verticalRange: range, animated: animated) + } + } + + func setupMainChart(verticalRange: ClosedRange, animated: Bool) { + mainLinesRenderer.setup(verticalRange: verticalRange, animated: animated) + horizontalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalScalesRenderer.setup(verticalRange: verticalRange, animated: animated) + verticalLineRenderer.setup(verticalRange: verticalRange, animated: animated) + lineBulletsRenerer.setup(verticalRange: verticalRange, animated: animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + super.updateChartsVisibility(visibility: visibility, animated: animated) + for (index, isVisible) in visibility.enumerated() { + mainLinesRenderer.setLineVisible(isVisible, at: index, animated: animated) + previewLinesChartRenderer.setLineVisible(isVisible, at: index, animated: animated) + lineBulletsRenerer.setLineVisible(isVisible, at: index, animated: animated) + } + updateChartVerticalRanges(horizontalRange: currentHorizontalMainChartRange, animated: true) + } + + override var currentMainRangeRenderer: BaseChartRenderer { + return mainLinesRenderer + } + + override var currentPreviewRangeRenderer: BaseChartRenderer { + return previewLinesChartRenderer + } + + override func showDetailsView(at chartPosition: CGFloat, detailsViewPosition: CGFloat, dataIndex: Int, date: Date, animted: Bool) { + super.showDetailsView(at: chartPosition, detailsViewPosition: detailsViewPosition, dataIndex: dataIndex, date: date, animted: animted) + verticalLineRenderer.values = [chartPosition] + verticalLineRenderer.isEnabled = true + + lineBulletsRenerer.isEnabled = true + lineBulletsRenerer.setVisible(true, animated: animted) + lineBulletsRenerer.bullets = chartLines.compactMap { chart in + return LineBulletsRenerer.Bullet(coordinate: chart.points[dataIndex], color: chart.color) + } + } + + override func hideDetailsView(animated: Bool) { + super.hideDetailsView(animated: animated) + + verticalLineRenderer.values = [] + verticalLineRenderer.isEnabled = false + lineBulletsRenerer.isEnabled = false + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + horizontalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.labelsColor = colorMode.chartLabelsColor + verticalScalesRenderer.axisXColor = colorMode.chartStrongLinesColor + verticalScalesRenderer.horizontalLinesColor = colorMode.chartHelperLinesColor + lineBulletsRenerer.setInnerColor(colorMode.chartBackgroundColor, animated: animated) + verticalLineRenderer.linesColor = colorMode.chartStrongLinesColor + } +} diff --git a/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift new file mode 100644 index 0000000000..ab836d00d2 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Controllers/Stacked Bars/StackedBarsChartController.swift @@ -0,0 +1,243 @@ +// +// StackedBarsChartController.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class StackedBarsChartController: BaseChartController { + let barsController: BarsComponentController + let zoomedBarsController: BarsComponentController + + override init(chartsCollection: ChartsCollection) { + let horizontalScalesRenderer = HorizontalScalesRenderer() + let verticalScalesRenderer = VerticalScalesRenderer() + barsController = BarsComponentController(isZoomed: false, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + zoomedBarsController = BarsComponentController(isZoomed: true, + mainBarsRenderer: BarChartRenderer(), + horizontalScalesRenderer: horizontalScalesRenderer, + verticalScalesRenderer: verticalScalesRenderer, + previewBarsChartRenderer: BarChartRenderer()) + + super.init(chartsCollection: chartsCollection) + + [barsController, zoomedBarsController].forEach { controller in + controller.chartFrame = { [unowned self] in self.chartFrame() } + controller.cartViewBounds = { [unowned self] in self.cartViewBounds() } + controller.zoomInOnDateClosure = { [unowned self] date in + self.didTapZoomIn(date: date) + } + controller.setChartTitleClosure = { [unowned self] (title, animated) in + self.setChartTitleClosure?(title, animated) + } + controller.setDetailsViewPositionClosure = { [unowned self] (position) in + self.setDetailsViewPositionClosure?(position) + } + controller.setDetailsChartVisibleClosure = { [unowned self] (visible, animated) in + self.setDetailsChartVisibleClosure?(visible, animated) + } + controller.setDetailsViewModel = { [unowned self] (viewModel, animated) in + self.setDetailsViewModel?(viewModel, animated) + } + controller.updatePreviewRangeClosure = { [unowned self] (fraction, animated) in + self.chartRangeUpdatedClosure?(fraction, animated) + } + controller.chartRangePagingClosure = { [unowned self] (isEnabled, pageSize) in + self.setChartRangePagingEnabled(isEnabled: isEnabled, minimumSelectionSize: pageSize) + } + } + } + + override var mainChartRenderers: [ChartViewRenderer] { + return [barsController.mainBarsRenderer, + zoomedBarsController.mainBarsRenderer, + barsController.horizontalScalesRenderer, + barsController.verticalScalesRenderer, +// performanceRenderer + ] + } + + override var navigationRenderers: [ChartViewRenderer] { + return [barsController.previewBarsChartRenderer, + zoomedBarsController.previewBarsChartRenderer] + } + + override func initializeChart() { + barsController.initialize(chartsCollection: initialChartsCollection, + initialDate: Date(), + totalHorizontalRange: BaseConstants.defaultRange, + totalVerticalRange: BaseConstants.defaultRange) + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: false) + } + + func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) { + if animated { + TimeInterval.setDefaultSuration(.expandAnimationDuration) + DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) { + TimeInterval.setDefaultSuration(.osXDuration) + } + } + + super.isZoomed = isZoomed + if isZoomed { + let toHorizontalRange = zoomedBarsController.initialHorizontalRange + let destinationHorizontalRange = (toHorizontalRange.lowerBound - barsController.barsWidth)...(toHorizontalRange.upperBound - barsController.barsWidth) + let verticalVisibleRange = barsController.currentVerticalMainChartRange + let initialVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) + + zoomedBarsController.mainBarsRenderer.setup(horizontalRange: barsController.currentHorizontalMainChartRange, animated: false) + zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.currentPreviewHorizontalRange, animated: false) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: initialVerticalRange, animated: false) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: initialVerticalRange, animated: false) + zoomedBarsController.mainBarsRenderer.setVisible(true, animated: false) + zoomedBarsController.previewBarsChartRenderer.setVisible(true, animated: false) + + barsController.setupMainChart(horizontalRange: destinationHorizontalRange, animated: animated) + barsController.previewBarsChartRenderer.setup(horizontalRange: zoomedBarsController.totalHorizontalRange, animated: animated) + barsController.mainBarsRenderer.setVisible(false, animated: animated) + barsController.previewBarsChartRenderer.setVisible(false, animated: animated) + + zoomedBarsController.willAppear(animated: animated) + barsController.willDisappear(animated: animated) + + zoomedBarsController.updateChartsVisibility(visibility: barsController.chartVisibility, animated: false) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: zoomedBarsController.currentVerticalMainChartRange, animated: animated, timeFunction: .easeOut) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: zoomedBarsController.currentPreviewVerticalRange, animated: animated, timeFunction: .easeOut) + } else { + if !zoomedBarsController.chartsCollection.isBlank { + barsController.hideDetailsView(animated: false) + barsController.chartVisibility = zoomedBarsController.chartVisibility + let visibleVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: barsController.visibleBars, + calculatingRange: barsController.initialHorizontalRange) ?? BaseConstants.defaultRange + barsController.mainBarsRenderer.setup(verticalRange: visibleVerticalRange, animated: false) + + let toHorizontalRange = barsController.initialHorizontalRange + + let verticalVisibleRange = barsController.initialVerticalRange + let targetVerticalRange = verticalVisibleRange.lowerBound...(verticalVisibleRange.upperBound + verticalVisibleRange.distance * 10) + + zoomedBarsController.setupMainChart(horizontalRange: toHorizontalRange, animated: animated) + zoomedBarsController.mainBarsRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.previewBarsChartRenderer.setup(verticalRange: targetVerticalRange, animated: animated, timeFunction: .easeIn) + zoomedBarsController.previewBarsChartRenderer.setup(horizontalRange: barsController.totalHorizontalRange, animated: animated) + DispatchQueue.main.asyncAfter(deadline: .now() + .defaultDuration) { [weak self] in + self?.zoomedBarsController.mainBarsRenderer.setVisible(false, animated: false) + self?.zoomedBarsController.previewBarsChartRenderer.setVisible(false, animated: false) + } + } + + barsController.willAppear(animated: animated) + zoomedBarsController.willDisappear(animated: animated) + + if !zoomedBarsController.chartsCollection.isBlank { + barsController.updateChartsVisibility(visibility: zoomedBarsController.chartVisibility, animated: false) + } + } + + self.setBackButtonVisibilityClosure?(isZoomed, animated) + } + + override func updateChartsVisibility(visibility: [Bool], animated: Bool) { + if isZoomed { + zoomedBarsController.updateChartsVisibility(visibility: visibility, animated: animated) + } else { + barsController.updateChartsVisibility(visibility: visibility, animated: animated) + } + } + + var visibleChartValues: [ChartsCollection.Chart] { + let visibility = isZoomed ? zoomedBarsController.chartVisibility : barsController.chartVisibility + let collection = isZoomed ? zoomedBarsController.chartsCollection : barsController.chartsCollection + let visibleCharts: [ChartsCollection.Chart] = visibility.enumerated().compactMap { args in + args.element ? collection.chartValues[args.offset] : nil + } + return visibleCharts + } + + override var actualChartVisibility: [Bool] { + return isZoomed ? zoomedBarsController.chartVisibility : barsController.chartVisibility + } + + override var actualChartsCollection: ChartsCollection { + return isZoomed ? zoomedBarsController.chartsCollection : barsController.chartsCollection + } + + override func chartInteractionDidBegin(point: CGPoint) { + if isZoomed { + zoomedBarsController.chartInteractionDidBegin(point: point) + } else { + barsController.chartInteractionDidBegin(point: point) + } + } + + override func chartInteractionDidEnd() { + if isZoomed { + zoomedBarsController.chartInteractionDidEnd() + } else { + barsController.chartInteractionDidEnd() + } + } + + override var drawChartVisibity: Bool { + return true + } + + override var currentChartHorizontalRangeFraction: ClosedRange { + if isZoomed { + return zoomedBarsController.currentChartHorizontalRangeFraction + } else { + return barsController.currentChartHorizontalRangeFraction + } + } + + override func cancelChartInteraction() { + if isZoomed { + return zoomedBarsController.hideDetailsView(animated: true) + } else { + return barsController.hideDetailsView(animated: true) + } + } + + override func didTapZoomIn(date: Date) { + guard isZoomed == false else { return } + if isZoomed { + return zoomedBarsController.hideDetailsView(animated: true) + } + self.getDetailsData?(date, { updatedCollection in + if let updatedCollection = updatedCollection { + self.zoomedBarsController.initialize(chartsCollection: updatedCollection, + initialDate: date, + totalHorizontalRange: 0...1, + totalVerticalRange: 0...1) + self.switchToChart(chartsCollection: updatedCollection, isZoomed: true, animated: true) + } + }) + } + + override func didTapZoomOut() { + cancelChartInteraction() + switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true) + } + + override func updateChartRange(_ rangeFraction: ClosedRange) { + if isZoomed { + return zoomedBarsController.chartRangeFractionDidUpdated(rangeFraction) + } else { + return barsController.chartRangeFractionDidUpdated(rangeFraction) + } + } + + override func apply(colorMode: ColorMode, animated: Bool) { + super.apply(colorMode: colorMode, animated: animated) + + zoomedBarsController.apply(colorMode: colorMode, animated: animated) + barsController.apply(colorMode: colorMode, animated: animated) + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift new file mode 100644 index 0000000000..73a6b52f42 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/BarChartRenderer.swift @@ -0,0 +1,293 @@ +// +// BarChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class BarChartRenderer: BaseChartRenderer { + struct BarsData { + static let blank = BarsData(barWidth: 1, locations: [], components: []) + var barWidth: CGFloat + var locations: [CGFloat] + var components: [Component] + + struct Component { + var color: UIColor + var values: [CGFloat] + } + } + + var fillToTop: Bool = false + private(set) lazy var selectedIndexAnimator: AnimationController = { + return AnimationController(current: 0, refreshClosure: self.refreshClosure) + }() + func setSelectedIndex(_ index: Int?, animated: Bool) { + let destinationValue: CGFloat = (index == nil) ? 0 : 1 + if animated { + if index != nil { + selectedBarIndex = index + } + self.selectedIndexAnimator.completionClosure = { + self.selectedBarIndex = index + } + guard self.selectedIndexAnimator.end != destinationValue else { return } + self.selectedIndexAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.selectedIndexAnimator.set(current: destinationValue) + self.selectedBarIndex = index + } + } + + private var selectedBarIndex: Int? { + didSet { + setNeedsDisplay() + } + } + var generalUnselectedAlpha: CGFloat = 0.5 + + private var componentsAnimators: [AnimationController] = [] + var bars: BarsData = BarsData(barWidth: 1, locations: [], components: []) { + willSet { + if bars.components.count != newValue.components.count { + componentsAnimators = newValue.components.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + private lazy var backgroundColorAnimator = AnimationController(current: UIColorContainer(color: .white), refreshClosure: refreshClosure) + func update(backgroundColor: UIColor, animated: Bool) { + if animated { + backgroundColorAnimator.animate(to: UIColorContainer(color: backgroundColor), duration: .defaultDuration) + } else { + backgroundColorAnimator.set(current: UIColorContainer(color: backgroundColor)) + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let chartsAlpha = chartAlphaAnimator.current + if chartsAlpha == 0 { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + var selectedPaths: [[CGRect]] = bars.components.map { _ in [] } + var unselectedPaths: [[CGRect]] = bars.components.map { _ in [] } + + if var barIndex = bars.locations.firstIndex(where: { $0 >= range.lowerBound }) { + if fillToTop { + barIndex = max(0, barIndex - 1) + + while barIndex < bars.locations.count { + let currentLocation = bars.locations[barIndex] + let right = transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame).roundedUpToPixelGrid() + let left = transform(toChartCoordinateHorizontal: currentLocation - bars.barWidth, chartFrame: chartFrame).roundedUpToPixelGrid() + + var summ: CGFloat = 0 + for (index, component) in bars.components.enumerated() { + summ += componentsAnimators[index].current * component.values[barIndex] + } + guard summ > 0 else { + barIndex += 1 + continue + } + + var stackedValue: CGFloat = 0 + for (index, component) in bars.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + let bottomFraction = stackedValue + let topFraction = stackedValue + ((component.values[barIndex] * visibilityPercent) / summ) + + let rect = CGRect(x: left, + y: chartFrame.maxY - chartFrame.height * topFraction, + width: right - left, + height: chartFrame.height * (topFraction - bottomFraction)) + if selectedBarIndex == barIndex { + selectedPaths[index].append(rect) + } else { + unselectedPaths[index].append(rect) + } + stackedValue = topFraction + } + if currentLocation > range.upperBound { + break + } + barIndex += 1 + } + + for (index, component) in bars.components.enumerated() { + context.saveGState() + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue).cgColor) + context.fill(selectedPaths[index]) + let resultAlpha: CGFloat = 1.0 - (1.0 - generalUnselectedAlpha) * selectedIndexAnimator.current + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue * resultAlpha).cgColor) + context.fill(unselectedPaths[index]) + context.restoreGState() + } + } else { + var selectedPaths: [[CGRect]] = bars.components.map { _ in [] } + barIndex = max(0, barIndex - 1) + + var currentLocation = bars.locations[barIndex] + var leftX = transform(toChartCoordinateHorizontal: currentLocation - bars.barWidth, chartFrame: chartFrame) + var rightX: CGFloat = 0 + + let startPoint = CGPoint(x: leftX, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + var backgourndPaths: [[CGPoint]] = bars.components.map { _ in Array() } + let itemsCount = ((bars.locations.count - barIndex) * 2) + 4 + for path in backgourndPaths.indices { + backgourndPaths[path].reserveCapacity(itemsCount) + backgourndPaths[path].append(startPoint) + } + var maxValues: [CGFloat] = bars.components.map { _ in 0 } + while barIndex < bars.locations.count { + currentLocation = bars.locations[barIndex] + rightX = transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame) + + var stackedValue: CGFloat = 0 + var bottomY: CGFloat = transform(toChartCoordinateVertical: stackedValue, chartFrame: chartFrame) + for (index, component) in bars.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + let height = component.values[barIndex] * visibilityPercent + stackedValue += height + let topY = transform(toChartCoordinateVertical: stackedValue, chartFrame: chartFrame) + let componentHeight = (bottomY - topY) + maxValues[index] = max(maxValues[index], componentHeight) + if selectedBarIndex == barIndex { + let rect = CGRect(x: leftX, + y: topY, + width: rightX - leftX, + height: componentHeight) + selectedPaths[index].append(rect) + } + backgourndPaths[index].append(CGPoint(x: leftX, y: topY)) + backgourndPaths[index].append(CGPoint(x: rightX, y: topY)) + bottomY = topY + } + if currentLocation > range.upperBound { + break + } + leftX = rightX + barIndex += 1 + } + + let endPoint = CGPoint(x: transform(toChartCoordinateHorizontal: currentLocation, chartFrame: chartFrame).roundedUpToPixelGrid(), + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + let colorOffset = Double((1.0 - (1.0 - generalUnselectedAlpha) * selectedIndexAnimator.current) * chartsAlpha) + + for (index, component) in bars.components.enumerated().reversed() { + if maxValues[index] < optimizationLevel { + continue + } + context.saveGState() + backgourndPaths[index].append(endPoint) + + context.setFillColor(UIColor.valueBetween(start: backgroundColorAnimator.current.color, + end: component.color, + offset: colorOffset).cgColor) + context.beginPath() + context.addLines(between: backgourndPaths[index]) + context.closePath() + context.fillPath() + context.restoreGState() + } + + for (index, component) in bars.components.enumerated().reversed() { + context.setFillColor(component.color.withAlphaComponent(chartsAlpha * component.color.alphaValue).cgColor) + context.fill(selectedPaths[index]) + } + } + } + } +} + +extension BarChartRenderer.BarsData { + static func initialComponents(chartsCollection: ChartsCollection) -> + (width: CGFloat, + chartBars: BarChartRenderer.BarsData, + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + let width: CGFloat + if chartsCollection.axisValues.count > 1 { + width = CGFloat(abs(chartsCollection.axisValues[1].timeIntervalSince1970 - chartsCollection.axisValues[0].timeIntervalSince1970)) + } else { + width = 1 + } + let components = chartsCollection.chartValues.map { BarChartRenderer.BarsData.Component(color: $0.color, + values: $0.values.map { CGFloat($0) }) } + let chartBars = BarChartRenderer.BarsData(barWidth: width, + locations: chartsCollection.axisValues.map { CGFloat($0.timeIntervalSince1970) }, + components: components) + + + + let totalVerticalRange = BarChartRenderer.BarsData.verticalRange(bars: chartBars) ?? 0...1 + let totalHorizontalRange = BarChartRenderer.BarsData.visibleHorizontalRange(bars: chartBars, width: width) ?? 0...1 + return (width: width, chartBars: chartBars, totalHorizontalRange: totalHorizontalRange, totalVerticalRange: totalVerticalRange) + } + + static func visibleHorizontalRange(bars: BarChartRenderer.BarsData, width: CGFloat) -> ClosedRange? { + guard let firstPoint = bars.locations.first, + let lastPoint = bars.locations.last, + firstPoint <= lastPoint else { + return nil + } + + return (firstPoint - width)...lastPoint + } + + static func verticalRange(bars: BarChartRenderer.BarsData, calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + guard bars.components.count > 0 else { + return nil + } + if let calculatingRange = calculatingRange { + guard var index = bars.locations.firstIndex(where: { $0 >= calculatingRange.lowerBound && $0 <= calculatingRange.upperBound }) else { + return nil + } + + var vMax: CGFloat = bars.components[0].values[index] + while index < bars.locations.count { + var summ: CGFloat = 0 + for component in bars.components { + summ += component.values[index] + } + vMax = max(vMax, summ) + + if bars.locations[index] > calculatingRange.upperBound { + break + } + index += 1 + } + return 0...vMax + } else { + var index = 0 + + var vMax: CGFloat = bars.components[0].values[index] + while index < bars.locations.count { + var summ: CGFloat = 0 + for component in bars.components { + summ += component.values[index] + } + vMax = max(vMax, summ) + index += 1 + } + return 0...vMax + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift new file mode 100644 index 0000000000..63627566e7 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/BaseChartRenderer.swift @@ -0,0 +1,116 @@ +// +// BaseChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let exponentialAnimationTrashold: CGFloat = 100 + +class BaseChartRenderer: ChartViewRenderer { + var containerViews: [UIView] = [] + + var optimizationLevel: CGFloat = 1 { + didSet { + setNeedsDisplay() + } + } + var isEnabled: Bool = true { + didSet { + setNeedsDisplay() + } + } + + private(set) lazy var chartAlphaAnimator: AnimationController = { + return AnimationController(current: 1, refreshClosure: self.refreshClosure) + }() + func setVisible(_ visible: Bool, animated: Bool) { + let destinationValue: CGFloat = visible ? 1 : 0 + guard self.chartAlphaAnimator.end != destinationValue else { return } + if animated { + self.chartAlphaAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.chartAlphaAnimator.set(current: destinationValue) + } + } + + lazy var horizontalRange = AnimationController>(current: 0...1, refreshClosure: refreshClosure) + lazy var verticalRange = AnimationController>(current: 0...1, refreshClosure: refreshClosure) + + func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + guard self.verticalRange.end != verticalRange else { + self.verticalRange.timeFunction = timeFunction ?? .linear + return + } + if animated { + let function: TimeFunction + if let timeFunction = timeFunction { + function = timeFunction + } else if self.verticalRange.current.distance > 0 && verticalRange.distance > 0 { + if self.verticalRange.current.distance / verticalRange.distance > exponentialAnimationTrashold { + function = .easeIn + } else if verticalRange.distance / self.verticalRange.current.distance > exponentialAnimationTrashold { + function = .easeOut + } else { + function = .linear + } + } else { + function = .linear + } + + self.verticalRange.animate(to: verticalRange, duration: .defaultDuration, timeFunction: function) + } else { + self.verticalRange.set(current: verticalRange) + } + } + + func setup(horizontalRange: ClosedRange, animated: Bool) { + guard self.horizontalRange.end != horizontalRange else { return } + if animated { + let animationCurve: TimeFunction = self.horizontalRange.current.distance > horizontalRange.distance ? .easeOut : .easeIn + self.horizontalRange.animate(to: horizontalRange, duration: .defaultDuration, timeFunction: animationCurve) + } else { + self.horizontalRange.set(current: horizontalRange) + } + } + + func transform(toChartCoordinateHorizontal x: CGFloat, chartFrame: CGRect) -> CGFloat { + return chartFrame.origin.x + (x - horizontalRange.current.lowerBound) / horizontalRange.current.distance * chartFrame.width + } + + func transform(toChartCoordinateVertical y: CGFloat, chartFrame: CGRect) -> CGFloat { + return chartFrame.height + chartFrame.origin.y - (y - verticalRange.current.lowerBound) / verticalRange.current.distance * chartFrame.height + } + + func transform(toChartCoordinate point: CGPoint, chartFrame: CGRect) -> CGPoint { + return CGPoint(x: transform(toChartCoordinateHorizontal: point.x, chartFrame: chartFrame), + y: transform(toChartCoordinateVertical: point.y, chartFrame: chartFrame)) + } + + func renderRange(bounds: CGRect, chartFrame: CGRect) -> ClosedRange { + let lowerBound = horizontalRange.current.lowerBound - chartFrame.origin.x / chartFrame.width * horizontalRange.current.distance + let upperBound = horizontalRange.current.upperBound + (bounds.width - chartFrame.width - chartFrame.origin.x) / chartFrame.width * horizontalRange.current.distance + guard lowerBound <= upperBound else { + print("Error: Unexpecated bounds range!") + return 0...1 + } + return lowerBound...upperBound + } + + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + fatalError("abstract") + } + + func setNeedsDisplay() { + containerViews.forEach { $0.setNeedsDisplay() } + } + + var refreshClosure: () -> Void { + return { [weak self] in + self?.setNeedsDisplay() + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift new file mode 100644 index 0000000000..ad61ff5dd9 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/ChartDetailsRenderer.swift @@ -0,0 +1,147 @@ +// +// ChartDetailsRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class ChartDetailsRenderer: BaseChartRenderer, ColorModeContainer { + private lazy var colorAnimator = AnimationController(current: 1, refreshClosure: refreshClosure) + private var fromColorMode: ColorMode = .day + private var currentColorMode: ColorMode = .day + func apply(colorMode: ColorMode, animated: Bool) { + if currentColorMode != colorMode { + fromColorMode = currentColorMode + currentColorMode = colorMode + if animated { + colorAnimator.set(current: 0) + colorAnimator.animate(to: 1, duration: .defaultDuration) + } else { + colorAnimator.set(current: 1) + } + } + } + + private var valuesAnimators: [AnimationController] = [] + func setValueVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + valuesAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + var detailsViewModel: ChartDetailsViewModel = .blank { + didSet { + if detailsViewModel.values.count != valuesAnimators.count { + valuesAnimators = detailsViewModel.values.map { _ in AnimationController(current: 1, refreshClosure: refreshClosure) } + } + setNeedsDisplay() + } + } + + var detailsViewPosition: CGFloat = 0 { + didSet { + setNeedsDisplay() + } + } + var detailViewPositionOffset: CGFloat = 10 + var detailViewTopOffset: CGFloat = 10 + private var iconWidth: CGFloat = 10 + private var margins: CGFloat = 10 + private let cornerRadius: CGFloat = 5 + private var rowHeight: CGFloat = 20 + private let titleFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let prefixFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let labelsFont = UIFont.systemFont(ofSize: 14, weight: .medium) + private let valuesFont = UIFont.systemFont(ofSize: 14, weight: .bold) + private let labelsColor: UIColor = .black + + private(set) var previousRenderBannerFrame: CGRect = .zero + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + previousRenderBannerFrame = .zero + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + + let widths: [(prefix: CGFloat, label: CGFloat, value: CGFloat)] = detailsViewModel.values.map { value in + var prefixWidth: CGFloat = 0 + if let prefixText = value.prefix { + prefixWidth = (prefixText as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: prefixFont], + context: nil).width.rounded(.up) + margins + } + + let labelWidth = (value.title as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: labelsFont], + context: nil).width.rounded(.up) + margins + + let valueWidth = (value.value as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: valuesFont], + context: nil).width.rounded(.up) + return (prefixWidth, labelWidth, valueWidth) + } + + let titleWidth = (detailsViewModel.title as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: [.font: titleFont], + context: nil).width + let prefixesWidth = widths.map { $0.prefix }.max() ?? 0 + let labelsWidth = widths.map { $0.label }.max() ?? 0 + let valuesWidth = widths.map { $0.value }.max() ?? 0 + + let totalWidth: CGFloat = max(prefixesWidth + labelsWidth + valuesWidth, titleWidth + iconWidth) + margins * 2 + let totalHeight: CGFloat = CGFloat(detailsViewModel.values.count + 1) * rowHeight + margins * 2 + let backgroundColor = UIColor.valueBetween(start: fromColorMode.chartDetailsViewColor, + end: currentColorMode.chartDetailsViewColor, + offset: Double(colorAnimator.current)) + let titleAndTextColor = UIColor.valueBetween(start: fromColorMode.chartDetailsTextColor, + end: currentColorMode.chartDetailsTextColor, + offset: Double(colorAnimator.current)) + let detailsViewFrame: CGRect + if totalWidth + detailViewTopOffset > detailsViewPosition { + detailsViewFrame = CGRect(x: detailsViewPosition + detailViewTopOffset, + y: detailViewTopOffset + chartFrame.minY, + width: totalWidth, + height: totalHeight) + } else { + detailsViewFrame = CGRect(x: detailsViewPosition - totalWidth - detailViewTopOffset, + y: detailViewTopOffset + chartFrame.minY, + width: totalWidth, + height: totalHeight) + } + previousRenderBannerFrame = detailsViewFrame + context.saveGState() + context.setFillColor(backgroundColor.cgColor) + context.beginPath() + context.addPath(CGPath(roundedRect: detailsViewFrame, cornerWidth: 5, cornerHeight: 5, transform: nil)) + context.fillPath() + context.endPage() + context.restoreGState() + + var drawY = detailsViewFrame.minY + margins + (rowHeight - titleFont.pointSize) / 2 + (detailsViewModel.title as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + margins, y: drawY), withAttributes: [.font: titleFont, + .foregroundColor: titleAndTextColor]) + drawY += rowHeight + + for (index, row) in widths.enumerated() { + let value = detailsViewModel.values[index] + if let prefixText = value.prefix { + (prefixText as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth - row.prefix, + y: drawY), + withAttributes: [.font: prefixText, .foregroundColor: titleAndTextColor]) + } + + (value.title as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth + margins, + y: drawY), + withAttributes: [.font: labelsFont, .foregroundColor: titleAndTextColor]) + + (value.value as NSString).draw(at: CGPoint(x: detailsViewFrame.minX + prefixesWidth + labelsWidth + valuesWidth - row.value + margins, + y: drawY), + withAttributes: [.font: labelsFont, .foregroundColor: value.color]) + + drawY += rowHeight + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift new file mode 100644 index 0000000000..3ab90ef546 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/HorizontalScalesRenderer.swift @@ -0,0 +1,99 @@ +// +// HorizontalScalesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class HorizontalScalesRenderer: BaseChartRenderer { + private var horizontalLabels: [LinesChartLabel] = [] + private var animatedHorizontalLabels: [AnimatedLinesChartLabels] = [] + + var labelsVerticalOffset: CGFloat = 8 + var labelsFont: UIFont = .systemFont(ofSize: 11) + var labelsColor: UIColor = .gray + + func setup(labels: [LinesChartLabel], animated: Bool) { + if animated { + var labelsToKeepVisible: [LinesChartLabel] = [] + let labelsToHide: [LinesChartLabel] + var labelsToShow: [LinesChartLabel] = [] + + for label in labels { + if horizontalLabels.contains(label) { + labelsToKeepVisible.append(label) + } else { + labelsToShow.append(label) + } + } + labelsToHide = horizontalLabels.filter { !labels.contains($0) } + animatedHorizontalLabels.removeAll() + horizontalLabels = labelsToKeepVisible + + let showAnimation = AnimatedLinesChartLabels(labels: labelsToShow, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + showAnimation.isAppearing = true + showAnimation.alphaAnimator.set(current: 0) + showAnimation.alphaAnimator.animate(to: 1, duration: .defaultDuration) + showAnimation.alphaAnimator.completionClosure = { [weak self, weak showAnimation] in + guard let self = self, let showAnimation = showAnimation else { return } + self.animatedHorizontalLabels.removeAll(where: { $0 === showAnimation }) + self.horizontalLabels = labels + } + + let hideAnimation = AnimatedLinesChartLabels(labels: labelsToHide, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + hideAnimation.isAppearing = false + hideAnimation.alphaAnimator.set(current: 1) + hideAnimation.alphaAnimator.animate(to: 0, duration: .defaultDuration) + hideAnimation.alphaAnimator.completionClosure = { [weak self, weak hideAnimation] in + guard let self = self, let hideAnimation = hideAnimation else { return } + self.animatedHorizontalLabels.removeAll(where: { $0 === hideAnimation }) + } + + animatedHorizontalLabels.append(showAnimation) + animatedHorizontalLabels.append(hideAnimation) + } else { + horizontalLabels = labels + animatedHorizontalLabels = [] + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let itemsAlpha = chartAlphaAnimator.current + guard itemsAlpha > 0 else { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + func drawHorizontalLabels(_ labels: [LinesChartLabel], color: UIColor) { + let attributes: [NSAttributedString.Key : Any] = [.foregroundColor: color, + .font: labelsFont] + let y = chartFrame.origin.y + chartFrame.height + labelsVerticalOffset + + if let start = labels.firstIndex(where: { $0.value > range.lowerBound }) { + for index in start.. range.upperBound { + break + } + } + } + } + let labelColorAlpha = labelsColor.alphaValue * itemsAlpha + drawHorizontalLabels(horizontalLabels, color: labelsColor.withAlphaComponent(labelColorAlpha * itemsAlpha)) + for animation in animatedHorizontalLabels { + let color = labelsColor.withAlphaComponent(animation.alphaAnimator.current * labelColorAlpha) + drawHorizontalLabels(animation.labels, color: color) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift b/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift new file mode 100644 index 0000000000..e0417719d7 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/LineBulletsRenerer.swift @@ -0,0 +1,67 @@ +// +// LineBulletsRenerer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LineBulletsRenerer: BaseChartRenderer { + struct Bullet { + var coordinate: CGPoint + var color: UIColor + } + + var bullets: [Bullet] = [] { + willSet { + if alphaAnimators.count != newValue.count { + alphaAnimators = newValue.map { _ in AnimationController(current: 1.0, refreshClosure: refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + private var alphaAnimators: [AnimationController] = [] + + private lazy var innerColorAnimator = AnimationController(current: UIColorContainer(color: .white), refreshClosure: refreshClosure) + public func setInnerColor(_ color: UIColor, animated: Bool) { + if animated { + innerColorAnimator.animate(to: UIColorContainer(color: color), duration: .defaultDuration) + } else { + innerColorAnimator.set(current: UIColorContainer(color: color)) + } + } + + var linesWidth: CGFloat = 2 + var bulletRadius: CGFloat = 6 + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + + for (index, bullet) in bullets.enumerated() { + let alpha = alphaAnimators[index].current + if alpha == 0 { continue } + + let centerX = transform(toChartCoordinateHorizontal: bullet.coordinate.x, chartFrame: chartFrame) + let centerY = transform(toChartCoordinateVertical: bullet.coordinate.y, chartFrame: chartFrame) + context.setFillColor(innerColorAnimator.current.color.withAlphaComponent(alpha).cgColor) + context.setStrokeColor(bullet.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(linesWidth) + let rect = CGRect(x: centerX - bulletRadius / 2, + y: centerY - bulletRadius / 2, + width: bulletRadius, + height: bulletRadius) + context.fillEllipse(in: rect) + context.strokeEllipse(in: rect) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift new file mode 100644 index 0000000000..fe3cdd47ab --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/LinesChartRenderer.swift @@ -0,0 +1,538 @@ +// +// LinesChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class LinesChartRenderer: BaseChartRenderer { + struct LineData { + var color: UIColor + var points: [CGPoint] + } + + private var linesAlphaAnimators: [AnimationController] = [] + + var lineWidth: CGFloat = 1 { + didSet { + setNeedsDisplay() + } + } + private lazy var linesShapeAnimator = AnimationController(current: 1, refreshClosure: self.refreshClosure) + private var fromLines: [LineData] = [] + private var toLines: [LineData] = [] + + func setLines(lines: [LineData], animated: Bool) { + if toLines.count != lines.count { + linesAlphaAnimators = lines.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + if animated { + self.fromLines = self.toLines + self.toLines = lines + linesShapeAnimator.set(current: 1.0 - linesShapeAnimator.current) + linesShapeAnimator.completionClosure = { + self.fromLines = [] + } + linesShapeAnimator.animate(to: 1, duration: .defaultDuration) + } else { + self.fromLines = [] + self.toLines = lines + linesShapeAnimator.set(current: 1) + } + } + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + linesAlphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let chartsAlpha = chartAlphaAnimator.current + if chartsAlpha == 0 { return } + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + for (index, toLine) in toLines.enumerated() { + let alpha = linesAlphaAnimators[index].current * chartsAlpha + if alpha == 0 { continue } + context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(lineWidth) + + if linesShapeAnimator.isAnimating { + let animationOffset = linesShapeAnimator.current + + let path = CGMutablePath() + let fromPoints = fromLines.safeElement(at: index)?.points ?? [] + let toPoints = toLines.safeElement(at: index)?.points ?? [] + + var fromIndex: Int? = fromPoints.firstIndex(where: { $0.x >= range.lowerBound }) + var toIndex: Int? = toPoints.firstIndex(where: { $0.x >= range.lowerBound }) + + let fromRange = verticalRange.start + let currentRange = verticalRange.current + let toRange = verticalRange.end + + func convertFromPoint(_ fromPoint: CGPoint) -> CGPoint { + return CGPoint(x: fromPoint.x, + y: (fromPoint.y - fromRange.lowerBound) / fromRange.distance * currentRange.distance + currentRange.lowerBound) + } + + func convertToPoint(_ toPoint: CGPoint) -> CGPoint { + return CGPoint(x: toPoint.x, + y: (toPoint.y - toRange.lowerBound) / toRange.distance * currentRange.distance + currentRange.lowerBound) + } + + var previousFromPoint: CGPoint + var previousToPoint: CGPoint + let startFromPoint: CGPoint? + let startToPoint: CGPoint? + + if let validFrom = fromIndex { + previousFromPoint = convertFromPoint(fromPoints[max(0, validFrom - 1)]) + startFromPoint = previousFromPoint + } else { + previousFromPoint = .zero + startFromPoint = nil + } + if let validTo = toIndex { + previousToPoint = convertToPoint(toPoints[max(0, validTo - 1)]) + startToPoint = previousToPoint + } else { + previousToPoint = .zero + startToPoint = nil + } + + var combinedPoints: [CGPoint] = [] + + func add(pointToDraw: CGPoint) { + if let startFromPoint = startFromPoint, + pointToDraw.x < startFromPoint.x { + let animatedPoint = CGPoint(x: pointToDraw.x, + y: CGFloat.valueBetween(start: startFromPoint.y, end: pointToDraw.y, offset: animationOffset)) + combinedPoints.append(transform(toChartCoordinate: animatedPoint, chartFrame: chartFrame)) + } else if let startToPoint = startToPoint, + pointToDraw.x < startToPoint.x { + let animatedPoint = CGPoint(x: pointToDraw.x, + y: CGFloat.valueBetween(start: startToPoint.y, end: pointToDraw.y, offset: 1 - animationOffset)) + combinedPoints.append(transform(toChartCoordinate: animatedPoint, chartFrame: chartFrame)) + } else { + combinedPoints.append(transform(toChartCoordinate: pointToDraw, chartFrame: chartFrame)) + } + } + + if previousToPoint != .zero && previousFromPoint != .zero { + add(pointToDraw: (previousToPoint.x < previousFromPoint.x ? previousToPoint : previousFromPoint)) + } else if previousToPoint != .zero { + add(pointToDraw: previousToPoint) + } else if previousFromPoint != .zero { + add(pointToDraw: previousFromPoint) + } + + while let validFromIndex = fromIndex, + let validToIndex = toIndex, + validFromIndex < fromPoints.count, + validToIndex < toPoints.count { + let currentFromPoint = convertFromPoint(fromPoints[validFromIndex]) + let currentToPoint = convertToPoint(toPoints[validToIndex]) + let pointToAdd: CGPoint + if currentFromPoint.x == currentToPoint.x { + pointToAdd = CGPoint.valueBetween(start: currentFromPoint, end: currentToPoint, offset: animationOffset) + previousFromPoint = currentFromPoint + previousToPoint = currentToPoint + fromIndex = validFromIndex + 1 + toIndex = validToIndex + 1 + } else if currentFromPoint.x < currentToPoint.x { + if previousToPoint.x < currentFromPoint.x { + let offset = Double((currentFromPoint.x - previousToPoint.x) / (currentToPoint.x - previousToPoint.x)) + let intermidiateToPoint = CGPoint.valueBetween(start: previousToPoint, end: currentToPoint, offset: offset) + pointToAdd = CGPoint.valueBetween(start: currentFromPoint, end: intermidiateToPoint, offset: animationOffset) + } else { + pointToAdd = currentFromPoint + } + previousFromPoint = currentFromPoint + fromIndex = validFromIndex + 1 + } else { + if previousFromPoint.x < currentToPoint.x { + let offset = Double((currentToPoint.x - previousFromPoint.x) / (currentFromPoint.x - previousFromPoint.x)) + let intermidiateFromPoint = CGPoint.valueBetween(start: previousFromPoint, end: currentFromPoint, offset: offset) + pointToAdd = CGPoint.valueBetween(start: intermidiateFromPoint, end: currentToPoint, offset: animationOffset) + } else { + pointToAdd = currentToPoint + } + previousToPoint = currentToPoint + toIndex = validToIndex + 1 + } + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + } + + while let validToIndex = toIndex, validToIndex < toPoints.count { + var pointToAdd = convertToPoint(toPoints[validToIndex]) + pointToAdd.y = CGFloat.valueBetween(start: previousFromPoint.y, + end: pointToAdd.y, + offset: animationOffset) + + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + + toIndex = validToIndex + 1 + } + + while let validFromIndex = fromIndex, validFromIndex < fromPoints.count { + var pointToAdd = convertFromPoint(fromPoints[validFromIndex]) + pointToAdd.y = CGFloat.valueBetween(start: previousToPoint.y, + end: pointToAdd.y, + offset: 1 - animationOffset) + + add(pointToDraw: pointToAdd) + if (pointToAdd.x > range.upperBound) { + break + } + + fromIndex = validFromIndex + 1 + } + + var index = 0 + var lines: [CGPoint] = [] + var currentChartPoint = combinedPoints[index] + lines.append(currentChartPoint) + + var chartPoints = [currentChartPoint] + var minIndex = 0 + var maxIndex = 0 + index += 1 + + while index < combinedPoints.count { + currentChartPoint = combinedPoints[index] + + if currentChartPoint.x - chartPoints[0].x < lineWidth * optimizationLevel { + chartPoints.append(currentChartPoint) + + if currentChartPoint.y > chartPoints[maxIndex].y { + maxIndex = chartPoints.count - 1 + } + if currentChartPoint.y < chartPoints[minIndex].y { + minIndex = chartPoints.count - 1 + } + + index += 1 + } else { + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + chartPoints[0] = currentChartPoint + index += 1 + minIndex = 0 + maxIndex = 0 + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[maxIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[maxIndex]] + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[minIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[minIndex]] + } + } + if chartPoints.count == 2 { + if chartPoints[0].y < chartPoints[1].y { + minIndex = 0 + maxIndex = 1 + } else { + minIndex = 1 + maxIndex = 0 + } + } else { + minIndex = 0 + maxIndex = 0 + } + } + } + } + + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } + } + + if (lines.count % 2) == 1 { + lines.removeLast() + } + + context.setLineCap(.round) + context.strokeLineSegments(between: lines) + + } else { + let alpha = linesAlphaAnimators[index].current * chartsAlpha + if alpha == 0 { continue } + context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) + context.setLineWidth(lineWidth) + + if var index = toLine.points.firstIndex(where: { $0.x >= range.lowerBound }) { + var lines: [CGPoint] = [] + index = max(0, index - 1) + var currentPoint = toLine.points[index] + var currentChartPoint = transform(toChartCoordinate: currentPoint, chartFrame: chartFrame) + lines.append(currentChartPoint) + //context.move(to: currentChartPoint) + + var chartPoints = [currentChartPoint] + var minIndex = 0 + var maxIndex = 0 + index += 1 + + while index < toLine.points.count { + currentPoint = toLine.points[index] + currentChartPoint = transform(toChartCoordinate: currentPoint, chartFrame: chartFrame) + + if currentChartPoint.x - chartPoints[0].x < lineWidth * optimizationLevel { + chartPoints.append(currentChartPoint) + + if currentChartPoint.y > chartPoints[maxIndex].y { + maxIndex = chartPoints.count - 1 + } + if currentChartPoint.y < chartPoints[minIndex].y { + minIndex = chartPoints.count - 1 + } + + index += 1 + } else { + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + chartPoints[0] = currentChartPoint + index += 1 + minIndex = 0 + maxIndex = 0 + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[maxIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[maxIndex]] + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + chartPoints = [chartPoints[minIndex], chartPoints.last!] + } else { + chartPoints = [chartPoints[minIndex]] + } + } + if chartPoints.count == 2 { + if chartPoints[0].y < chartPoints[1].y { + minIndex = 0 + maxIndex = 1 + } else { + minIndex = 1 + maxIndex = 0 + } + } else { + minIndex = 0 + maxIndex = 0 + } + } + } + if currentPoint.x > range.upperBound { + break + } + } + + if chartPoints.count == 1 { + lines.append(currentChartPoint) + lines.append(currentChartPoint) + } else { + if minIndex < maxIndex { + if minIndex != 0 { + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + } + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + if maxIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } else { + if maxIndex != 0 { + lines.append(chartPoints[maxIndex]) + lines.append(chartPoints[maxIndex]) + } + lines.append(chartPoints[minIndex]) + lines.append(chartPoints[minIndex]) + if minIndex != chartPoints.count - 1 { + lines.append(chartPoints.last!) + lines.append(chartPoints.last!) + } + } + } + + if (lines.count % 2) == 1 { + lines.removeLast() + } + + context.setLineCap(.round) + context.strokeLineSegments(between: lines) + } + +// if var start = toLine.points.firstIndex(where: { $0.x > range.lowerBound }) { +// let alpha = linesAlphaAnimators[index].current * chartsAlpha +// if alpha == 0 { continue } +// context.setStrokeColor(toLine.color.withAlphaComponent(alpha).cgColor) +// context.setLineWidth(lineWidth) +// +// context.setLineCap(.round) +// start = max(0, start - 1) +// let startPoint = toLine.points[start] +// var lines: [CGPoint] = [] +// var pointToDraw = CGPoint(x: transform(toChartCoordinateHorizontal: startPoint.x, chartFrame: chartFrame), +// y: transform(toChartCoordinateVertical: startPoint.y, chartFrame: chartFrame)) +// for index in (start + 1).. range.upperBound { +// break +// } +// } +// +// context.strokeLineSegments(between: lines) +// } + } + } + } +} + +extension LinesChartRenderer.LineData { + static func initialComponents(chartsCollection: ChartsCollection) -> (linesData: [LinesChartRenderer.LineData], + totalHorizontalRange: ClosedRange, + totalVerticalRange: ClosedRange) { + let lines: [LinesChartRenderer.LineData] = chartsCollection.chartValues.map { chart in + let points = chart.values.enumerated().map({ (arg) -> CGPoint in + return CGPoint(x: chartsCollection.axisValues[arg.offset].timeIntervalSince1970, + y: arg.element) + }) + return LinesChartRenderer.LineData(color: chart.color, points: points) + } + let horizontalRange = LinesChartRenderer.LineData.horizontalRange(lines: lines) ?? BaseConstants.defaultRange + let verticalRange = LinesChartRenderer.LineData.verticalRange(lines: lines) ?? BaseConstants.defaultRange + return (linesData: lines, totalHorizontalRange: horizontalRange, totalVerticalRange: verticalRange) + } + + static func horizontalRange(lines: [LinesChartRenderer.LineData]) -> ClosedRange? { + guard let firstPoint = lines.first?.points.first else { return nil } + var hMin: CGFloat = firstPoint.x + var hMax: CGFloat = firstPoint.x + + for line in lines { + if let first = line.points.first, + let last = line.points.last { + hMin = min(hMin, first.x) + hMax = max(hMax, last.x) + } + } + + return hMin...hMax + } + + static func verticalRange(lines: [LinesChartRenderer.LineData], calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + if let calculatingRange = calculatingRange { + guard let initalStart = lines.first?.points.first(where: { $0.x >= calculatingRange.lowerBound && + $0.x <= calculatingRange.upperBound }) else { return nil } + var vMin: CGFloat = initalStart.y + var vMax: CGFloat = initalStart.y + for line in lines { + if var index = line.points.firstIndex(where: { $0.x > calculatingRange.lowerBound }) { + if addBounds { + index = max(0, index - 1) + } + while index < line.points.count { + let point = line.points[index] + if point.x < calculatingRange.upperBound { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } else if addBounds { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + break + } else { + break + } + index += 1 + } + } + } + return vMin...vMax + } else { + guard let firstPoint = lines.first?.points.first else { return nil } + var vMin: CGFloat = firstPoint.y + var vMax: CGFloat = firstPoint.y + for line in lines { + for point in line.points { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } + } + return vMin...vMax + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift new file mode 100644 index 0000000000..07ff3daaaa --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PecentChartRenderer.swift @@ -0,0 +1,132 @@ +// +// PecentChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PecentChartRenderer: BaseChartRenderer { + struct PercentageData { + static let blank = PecentChartRenderer.PercentageData(locations: [], components: []) + var locations: [CGFloat] + var components: [Component] + + struct Component { + var color: UIColor + var values: [CGFloat] + } + } + + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + private var componentsAnimators: [AnimationController] = [] + var percentageData: PercentageData = PercentageData(locations: [], components: []) { + willSet { + if percentageData.components.count != newValue.components.count { + componentsAnimators = newValue.components.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + } + } + didSet { + setNeedsDisplay() + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let alpha = chartAlphaAnimator.current + guard alpha > 0 else { return } + + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + var paths: [CGMutablePath] = percentageData.components.map { _ in CGMutablePath() } + var vertices: [CGFloat] = Array(repeating: 0, count: percentageData.components.count) + + if var locationIndex = percentageData.locations.firstIndex(where: { $0 > range.lowerBound }) { + locationIndex = max(0, locationIndex - 1) + + var currentLocation = transform(toChartCoordinateHorizontal: percentageData.locations[locationIndex], chartFrame: chartFrame) + + let startPoint = CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + for path in paths { + path.move(to: startPoint) + } + paths.last?.addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + + while locationIndex < percentageData.locations.count { + currentLocation = transform(toChartCoordinateHorizontal: percentageData.locations[locationIndex], chartFrame: chartFrame) + var summ: CGFloat = 0 + + for (index, component) in percentageData.components.enumerated() { + let visibilityPercent = componentsAnimators[index].current + + let value = component.values[locationIndex] * visibilityPercent + if index == 0 { + vertices[index] = value + } else { + vertices[index] = value + vertices[index - 1] + } + summ += value + } + + if summ > 0 { + for (index, value) in vertices.dropLast().enumerated() { + paths[index].addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: value / summ, chartFrame: chartFrame))) + } + } + + if currentLocation > range.upperBound { + break + } + + locationIndex += 1 + } + + paths.last?.addLine(to: CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + + let endPoint = CGPoint(x: currentLocation, + y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + + for (index, path) in paths.enumerated().reversed() { + let visibilityPercent = componentsAnimators[index].current + if visibilityPercent == 0 { continue } + + path.addLine(to: endPoint) + path.closeSubpath() + + context.saveGState() + context.beginPath() + context.addPath(path) + + context.setFillColor(percentageData.components[index].color.cgColor) + context.fillPath() + context.restoreGState() + } + } + } +} + +extension PecentChartRenderer.PercentageData { + static func horizontalRange(data: PecentChartRenderer.PercentageData) -> ClosedRange? { + guard let firstPoint = data.locations.first, + let lastPoint = data.locations.last, + firstPoint <= lastPoint else { + return nil + } + + return firstPoint...lastPoint + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift new file mode 100644 index 0000000000..e36fdaf913 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PercentPieAnimationRenderer.swift @@ -0,0 +1,202 @@ +// +// PercentPieAnimationRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PercentPieAnimationRenderer: BaseChartRenderer { + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + private lazy var transitionAnimator = AnimationController(current: 0, refreshClosure: refreshClosure) + private var animationComponentsPoints: [[CGPoint]] = [] + var visiblePercentageData: PecentChartRenderer.PercentageData = .blank { + didSet { + animationComponentsPoints = [] + } + } + var visiblePieComponents: [PieChartRenderer.PieComponent] = [] + + func animate(fromDataToPie: Bool, animated: Bool, completion: @escaping () -> Void) { + assert(visiblePercentageData.components.count == visiblePieComponents.count) + + isEnabled = true + transitionAnimator.completionClosure = { [weak self] in + self?.isEnabled = false + completion() + } + transitionAnimator.animate(to: fromDataToPie ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + private func generateAnimationComponentPoints(bounds: CGRect, chartFrame: CGRect) { + let range = renderRange(bounds: bounds, chartFrame: chartFrame) + + let componentsCount = visiblePercentageData.components.count + guard componentsCount > 0 else { return } + animationComponentsPoints = visiblePercentageData.components.map { _ in [] } + var vertices: [CGFloat] = Array(repeating: 0, count: visiblePercentageData.components.count) + + if var locationIndex = visiblePercentageData.locations.firstIndex(where: { $0 > range.lowerBound }) { + locationIndex = max(0, locationIndex - 1) + var currentLocation = transform(toChartCoordinateHorizontal: visiblePercentageData.locations[locationIndex], chartFrame: chartFrame) + let startPoint = CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + for index in 0.. range.upperBound { + break + } + locationIndex += 1 + } + + animationComponentsPoints[componentsCount - 1].append(CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.upperBound, chartFrame: chartFrame))) + let endPoint = CGPoint(x: currentLocation, y: transform(toChartCoordinateVertical: verticalRange.current.lowerBound, chartFrame: chartFrame)) + for index in 0.. 0 && verticalRange.current.distance > 0 else { return } + self.optimizationLevel = 1 + + if animationComponentsPoints.isEmpty { + generateAnimationComponentPoints(bounds: bounds, chartFrame: chartFrame) + } + + let numberOfComponents = animationComponentsPoints.count + guard numberOfComponents > 0 else { return } + let destinationRadius = max(chartFrame.width, chartFrame.height) + + let animationFraction = transitionAnimator.current + let animationFractionD = Double(transitionAnimator.current) + let easeInAnimationFractionD = animationFractionD * animationFractionD * animationFractionD * animationFractionD + let center = CGPoint(x: chartFrame.midX, y: chartFrame.midY) + let totalPieSumm: CGFloat = visiblePieComponents.map { $0.value } .reduce(0, +) + + let pathsToDraw: [CGMutablePath] = (0.. 4 else { + return + } + + let percent = visiblePieComponents[componentIndex].value / totalPieSumm + let segmentSize = 2 * .pi * percent + let endAngle = startAngle + segmentSize + let centerAngle = (startAngle + endAngle) / 2 + + let lineCenterPoint = CGPoint.valueBetween(start: componentPoints[componentPoints.count / 2], + end: center, + offset: animationFractionD) + + let startDestinationPoint = lineCenterPoint + CGPoint(x: destinationRadius, y: 0) + let centerDestinationPoint = lineCenterPoint + CGPoint(x: 0, y: destinationRadius) + let endDestinationPoint = lineCenterPoint + CGPoint(x: -destinationRadius, y: 0) + let initialStartDestinationAngle: CGFloat = 0 + let initialCenterDestinationAngle: CGFloat = .pi / 2 + let initialEndDestinationAngle: CGFloat = .pi + + var previousAddedPoint = (componentPoints[0] * 2 - center) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: centerAngle - initialCenterDestinationAngle, offset: animationFractionD)) + + pathsToDraw[componentIndex].move(to: previousAddedPoint) + + func addPointToPath(_ point: CGPoint) { + if (point - previousAddedPoint).lengthSquared() > optimizationLevel { + pathsToDraw[componentIndex].addLine(to: point) + previousAddedPoint = point + } + } + + for endPointIndex in 1..<(componentPoints.count / 2) { + addPointToPath(CGPoint.valueBetween(start: componentPoints[endPointIndex], end: endDestinationPoint, offset: easeInAnimationFractionD) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: endAngle - initialEndDestinationAngle, offset: animationFractionD))) + } + + addPointToPath(lineCenterPoint) + + for startPointIndex in (componentPoints.count / 2 + 1)..<(componentPoints.count - 1) { + addPointToPath(CGPoint.valueBetween(start: componentPoints[startPointIndex], end: startDestinationPoint, offset: easeInAnimationFractionD) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: startAngle - initialStartDestinationAngle, offset: animationFractionD))) + } + + if let lastPoint = componentPoints.last { + addPointToPath((lastPoint * 2 - center) + .rotate(origin: lineCenterPoint, angle: CGFloat.valueBetween(start: 0, end: centerAngle - initialCenterDestinationAngle, offset: animationFractionD))) + } + + startAngle = endAngle + } + + if let lastPath = animationComponentsPoints.last { + pathsToDraw.last?.addLines(between: lastPath) + } + + for (index, path) in pathsToDraw.enumerated().reversed() { + path.closeSubpath() + + context.saveGState() + context.beginPath() + context.addPath(path) + + context.setFillColor(visiblePieComponents[index].color.cgColor) + context.fillPath() + context.restoreGState() + } + + let diagramRadius = (min(chartFrame.width, chartFrame.height) / 2) * 0.925 + let targetFrame = CGRect(origin: CGPoint(x: center.x - diagramRadius, + y: center.y - diagramRadius), + size: CGSize(width: diagramRadius * 2, + height: diagramRadius * 2)) + + let minX = animationComponentsPoints.last?.first?.x ?? 0 + let maxX = animationComponentsPoints.last?.last?.x ?? 0 + let startFrame = CGRect(x: minX, + y: chartFrame.minY, + width: maxX - minX, + height: chartFrame.height) + let cornerRadius = diagramRadius * animationFraction + let fadeOutFrame = CGRect.valueBetween(start: startFrame, end: targetFrame, offset: animationFractionD) + let fadeOutPath = CGMutablePath() + fadeOutPath.addRect(bounds) + fadeOutPath.addPath(CGPath(roundedRect: fadeOutFrame, cornerWidth: cornerRadius, cornerHeight: cornerRadius, transform: nil)) + + context.saveGState() + context.beginPath() + context.addPath(fadeOutPath) + context.setFillColor(backgroundColor.cgColor) + context.fillPath(using: .evenOdd) + context.restoreGState() + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift new file mode 100644 index 0000000000..c17663ce5f --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PerformanceRenderer.swift @@ -0,0 +1,31 @@ +// +// PerformanceRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/10/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PerformanceRenderer: ChartViewRenderer { + var containerViews: [UIView] = [] + + private var previousTickTime: TimeInterval = CACurrentMediaTime() + + func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + let currentTime = CACurrentMediaTime() + let delta = currentTime - previousTickTime + previousTickTime = currentTime + + let normalDelta = 0.017 + let redDelta = 0.05 + + if delta > normalDelta || delta < 0.75 { + let green = CGFloat( 1.0 - crop(0, (delta - normalDelta) / (redDelta - normalDelta), 1)) + let color = UIColor(red: 1.0, green: green, blue: 0, alpha: 1) + context.setFillColor(color.cgColor) + context.fill(CGRect(x: 0, y: 0, width: bounds.width, height: 3)) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift new file mode 100644 index 0000000000..ed4e6bdd49 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/PieChartRenderer.swift @@ -0,0 +1,191 @@ +// +// PieChartRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class PieChartRenderer: BaseChartRenderer { + struct PieComponent: Hashable { + var color: UIColor + var value: CGFloat + } + + override func setup(verticalRange: ClosedRange, animated: Bool, timeFunction: TimeFunction? = nil) { + super.setup(verticalRange: 0...1, animated: animated, timeFunction: timeFunction) + } + + var valuesFormatter: NumberFormatter = NumberFormatter() + var drawValues: Bool = true + + private var componentsAnimators: [AnimationController] = [] + private lazy var transitionAnimator: AnimationController = { AnimationController(current: 1, refreshClosure: self.refreshClosure) }() + private var oldPercentageData: [PieComponent] = [] + private var percentageData: [PieComponent] = [] + private var setlectedSegmentsAnimators: [AnimationController] = [] + + var drawPie: Bool = true + var initialAngle: CGFloat = .pi / 3 + var hasSelectedSegments: Bool { + return selectedSegment != nil + } + private(set) var selectedSegment: Int? + func selectSegmentAt(at indexToSelect: Int?, animated: Bool) { + selectedSegment = indexToSelect + for (index, animator) in setlectedSegmentsAnimators.enumerated() { + let fraction: CGFloat = (index == indexToSelect) ? 1.0 : 0.0 + if animated { + animator.animate(to: fraction, duration: .defaultDuration / 2) + } else { + animator.set(current: fraction) + } + } + } + + func updatePercentageData(_ percentageData: [PieComponent], animated: Bool) { + if self.percentageData.count != percentageData.count { + componentsAnimators = percentageData.map { _ in AnimationController(current: 1, refreshClosure: self.refreshClosure) } + setlectedSegmentsAnimators = percentageData.map { _ in AnimationController(current: 0, refreshClosure: self.refreshClosure) } + } + if animated { + self.oldPercentageData = self.currentTransitionAnimationData + self.percentageData = percentageData + transitionAnimator.completionClosure = { [weak self] in + self?.oldPercentageData = [] + } + transitionAnimator.set(current: 0) + transitionAnimator.animate(to: 1, duration: .defaultDuration) + } else { + self.oldPercentageData = [] + self.percentageData = percentageData + transitionAnimator.set(current: 0) + } + } + + func setComponentVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + componentsAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + var lastRenderedBounds: CGRect = .zero + var lastRenderedChartFrame: CGRect = .zero + func selectedItemIndex(at point: CGPoint) -> Int? { + let touchPosition = lastRenderedChartFrame.origin + point * lastRenderedChartFrame.size + let center = CGPoint(x: lastRenderedChartFrame.midX, y: lastRenderedChartFrame.midY) + let radius = min(lastRenderedChartFrame.width, lastRenderedChartFrame.height) / 2 + if center.distanceTo(touchPosition) > radius { return nil } + let angle = (center - touchPosition).angle + .pi + let currentData = currentlyVisibleData + let total: CGFloat = currentData.map({ $0.value }).reduce(0, +) + var startAngle: CGFloat = initialAngle + for (index, piece) in currentData.enumerated() { + let percent = piece.value / total + let segmentSize = 2 * .pi * percent + let endAngle = startAngle + segmentSize + if angle >= startAngle && angle <= endAngle || + angle + .pi * 2 >= startAngle && angle + .pi * 2 <= endAngle { + return index + } + startAngle = endAngle + } + return nil + } + + private var currentTransitionAnimationData: [PieComponent] { + if transitionAnimator.isAnimating { + let animationFraction = transitionAnimator.current + return percentageData.enumerated().map { arg in + return PieComponent(color: arg.element.color, + value: oldPercentageData[arg.offset].value * (1 - animationFraction) + arg.element.value * animationFraction) + } + } else { + return percentageData + } + } + + var currentlyVisibleData: [PieComponent] { + return currentTransitionAnimationData.enumerated().map { arg in + return PieComponent(color: arg.element.color, + value: arg.element.value * componentsAnimators[arg.offset].current) + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + lastRenderedBounds = bounds + lastRenderedChartFrame = chartFrame + let chartAlpha = chartAlphaAnimator.current + if chartAlpha == 0 { return } + + let center = CGPoint(x: chartFrame.midX, y: chartFrame.midY) + let radius = min(chartFrame.width, chartFrame.height) / 2 + + let currentData = currentlyVisibleData + + let total: CGFloat = currentData.map({ $0.value }).reduce(0, +) + guard total > 0 else { + return + } + + let animationSelectionOffset: CGFloat = radius / 15 + let maximumFontSize: CGFloat = radius / 7 + let minimumFontSize: CGFloat = 4 + let centerOffsetStartAngle = CGFloat.pi / 4 + let minimumValueToDraw: CGFloat = 0.01 + let diagramRadius = radius - animationSelectionOffset + + let numberOfVisibleItems = currentlyVisibleData.filter { $0.value > 0 }.count + var startAngle: CGFloat = initialAngle + for (index, piece) in currentData.enumerated() { + let percent = piece.value / total + guard percent > 0 else { continue } + let segmentSize = 2 * .pi * percent * chartAlpha + let endAngle = startAngle + segmentSize + let centerAngle = (startAngle + endAngle) / 2 + let labelVector = CGPoint(x: cos(centerAngle), + y: sin(centerAngle)) + + let selectionAnimationFraction = (numberOfVisibleItems > 1 ? setlectedSegmentsAnimators[index].current : 0) + + let updatedCenter = CGPoint(x: center.x + labelVector.x * selectionAnimationFraction * animationSelectionOffset, + y: center.y + labelVector.y * selectionAnimationFraction * animationSelectionOffset) + if drawPie { + context.saveGState() + context.setFillColor(piece.color.withAlphaComponent(piece.color.alphaValue * chartAlpha).cgColor) + context.move(to: updatedCenter) + context.addArc(center: updatedCenter, + radius: radius - animationSelectionOffset, + startAngle: startAngle, + endAngle: endAngle, + clockwise: false) + context.fillPath() + context.restoreGState() + } + + if drawValues && percent >= minimumValueToDraw { + context.saveGState() + + let text = valuesFormatter.string(from: percent * 100) + let fraction = crop(0, segmentSize / centerOffsetStartAngle, 1) + let fontSize = (minimumFontSize + (maximumFontSize - minimumFontSize) * fraction).rounded(.up) + let labelPotisionOffset = diagramRadius / 2 + diagramRadius / 2 * (1 - fraction) + let font = UIFont.systemFont(ofSize: fontSize, weight: .bold) + let labelsEaseInColor = crop(0, chartAlpha * chartAlpha * 2 - 1, 1) + let attributes: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white.withAlphaComponent(labelsEaseInColor), + .font: font] + let rect = (text as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: attributes, + context: nil) + let labelPoint = CGPoint(x: labelVector.x * labelPotisionOffset + updatedCenter.x - rect.width / 2, + y: labelVector.y * labelPotisionOffset + updatedCenter.y - rect.height / 2) + (text as NSString).draw(at: labelPoint, withAttributes: attributes) + context.restoreGState() + } + + startAngle = endAngle + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift new file mode 100644 index 0000000000..39d1f26a46 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/VerticalLinesRenderer.swift @@ -0,0 +1,42 @@ +// +// VerticalLinesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class VerticalLinesRenderer: BaseChartRenderer { + var values: [CGFloat] = [] { + didSet { + alphaAnimators = values.map { _ in AnimationController(current: 1.0, refreshClosure: refreshClosure) } + setNeedsDisplay() + } + } + private var alphaAnimators: [AnimationController] = [] + + var linesColor: UIColor = .black + var linesWidth: CGFloat = UIView.oneDevicePixel + + func setLineVisible(_ isVisible: Bool, at index: Int, animated: Bool) { + alphaAnimators[index].animate(to: isVisible ? 1 : 0, duration: animated ? .defaultDuration : 0) + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + + context.setLineWidth(linesWidth) + + for (index, value) in values.enumerated() { + let alpha = alphaAnimators[index].current + if alpha == 0 { continue } + + context.setStrokeColor(linesColor.withAlphaComponent(linesColor.alphaValue * alpha).cgColor) + let pointX = transform(toChartCoordinateHorizontal: value, chartFrame: chartFrame) + context.strokeLineSegments(between: [CGPoint(x: pointX, y: chartFrame.minY), + CGPoint(x: pointX, y: chartFrame.maxY)]) + } + } +} diff --git a/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift b/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift new file mode 100644 index 0000000000..79d9dcec22 --- /dev/null +++ b/submodules/Charts/Sources/Charts/Renderes/VerticalScalesRenderer.swift @@ -0,0 +1,162 @@ +// +// VerticalScalesRenderer.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class VerticalScalesRenderer: BaseChartRenderer { + private var verticalLabelsAndLines: [LinesChartLabel] = [] + private var animatedVerticalLabelsAndLines: [AnimatedLinesChartLabels] = [] + private lazy var horizontalLinesAlphaAnimator: AnimationController = { + return AnimationController(current: 1, refreshClosure: self.refreshClosure) + }() + + var drawAxisX: Bool = true + var axisXColor: UIColor = .black + var axisXWidth: CGFloat = UIView.oneDevicePixel + + var isRightAligned: Bool = false + + var horizontalLinesColor: UIColor = .black { + didSet { + setNeedsDisplay() + } + } + var horizontalLinesWidth: CGFloat = UIView.oneDevicePixel + var lavelsAsisOffset: CGFloat = 6 + var labelsColor: UIColor = .black { + didSet { + setNeedsDisplay() + } + } + var labelsFont: UIFont = .systemFont(ofSize: 11) + + func setHorizontalLinesVisible(_ visible: Bool, animated: Bool) { + let destinationValue: CGFloat = visible ? 1 : 0 + guard self.horizontalLinesAlphaAnimator.end != destinationValue else { return } + if animated { + self.horizontalLinesAlphaAnimator.animate(to: destinationValue, duration: .defaultDuration) + } else { + self.horizontalLinesAlphaAnimator.set(current: destinationValue) + } + } + + func setup(verticalLimitsLabels: [LinesChartLabel], animated: Bool) { + if animated { + var labelsToKeepVisible: [LinesChartLabel] = [] + let labelsToHide: [LinesChartLabel] + var labelsToShow: [LinesChartLabel] = [] + + for label in verticalLimitsLabels { + if verticalLabelsAndLines.contains(label) { + labelsToKeepVisible.append(label) + } else { + labelsToShow.append(label) + } + } + labelsToHide = verticalLabelsAndLines.filter { !verticalLimitsLabels.contains($0) } + animatedVerticalLabelsAndLines.removeAll(where: { $0.isAppearing }) + verticalLabelsAndLines = labelsToKeepVisible + + let showAnimation = AnimatedLinesChartLabels(labels: labelsToShow, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + showAnimation.isAppearing = true + showAnimation.alphaAnimator.set(current: 0) + showAnimation.alphaAnimator.animate(to: 1, duration: .defaultDuration) + showAnimation.alphaAnimator.completionClosure = { [weak self, weak showAnimation] in + guard let self = self, let showAnimation = showAnimation else { return } + self.animatedVerticalLabelsAndLines.removeAll(where: { $0 === showAnimation }) + self.verticalLabelsAndLines = verticalLimitsLabels + } + + let hideAnimation = AnimatedLinesChartLabels(labels: labelsToHide, alphaAnimator: AnimationController(current: 1.0, refreshClosure: refreshClosure)) + hideAnimation.isAppearing = false + hideAnimation.alphaAnimator.set(current: 1) + hideAnimation.alphaAnimator.animate(to: 0, duration: .defaultDuration) + hideAnimation.alphaAnimator.completionClosure = { [weak self, weak hideAnimation] in + guard let self = self, let hideAnimation = hideAnimation else { return } + self.animatedVerticalLabelsAndLines.removeAll(where: { $0 === hideAnimation }) + } + + animatedVerticalLabelsAndLines.append(showAnimation) + animatedVerticalLabelsAndLines.append(hideAnimation) + } else { + verticalLabelsAndLines = verticalLimitsLabels + animatedVerticalLabelsAndLines = [] + } + } + + override func render(context: CGContext, bounds: CGRect, chartFrame: CGRect) { + guard isEnabled && verticalRange.current.distance > 0 && verticalRange.current.distance > 0 else { return } + let generalAlpha = chartAlphaAnimator.current + if generalAlpha == 0 { return } + let labelColorAlpha = labelsColor.alphaValue + + func drawLines(_ labels: [LinesChartLabel], alpha: CGFloat) { + var lineSegments: [CGPoint] = [] + let x0 = chartFrame.minX + let x1 = chartFrame.maxX + + context.setStrokeColor(horizontalLinesColor.withAlphaComponent(horizontalLinesColor.alphaValue * alpha).cgColor) + + for lineInfo in labels { + let y = transform(toChartCoordinateVertical: lineInfo.value, chartFrame: chartFrame).roundedUpToPixelGrid() + lineSegments.append(CGPoint(x: x0, y: y)) + lineSegments.append(CGPoint(x: x1, y: y)) + } + context.strokeLineSegments(between: lineSegments) + } + + func drawVerticalLabels(_ labels: [LinesChartLabel], attributes: [NSAttributedString.Key: Any]) { + if isRightAligned { + for label in labels { + let y = transform(toChartCoordinateVertical: label.value, chartFrame: chartFrame) - labelsFont.pointSize - lavelsAsisOffset + + let rect = (label.text as NSString).boundingRect(with: bounds.size, + options: .usesLineFragmentOrigin, + attributes: attributes, + context: nil) + + (label.text as NSString).draw(at: CGPoint(x:chartFrame.maxX - rect.width, y: y), withAttributes: attributes) + } + } else { + for label in labels { + let y = transform(toChartCoordinateVertical: label.value, chartFrame: chartFrame) - labelsFont.pointSize - lavelsAsisOffset + + (label.text as NSString).draw(at: CGPoint(x:chartFrame.minX, y: y), withAttributes: attributes) + } + } + } + + let horizontalLinesAlpha = horizontalLinesAlphaAnimator.current + if horizontalLinesAlpha > 0 { + context.setLineWidth(horizontalLinesWidth) + + drawLines(verticalLabelsAndLines, alpha: generalAlpha) + for animatedLabesAndLines in animatedVerticalLabelsAndLines { + drawLines(animatedLabesAndLines.labels, alpha: animatedLabesAndLines.alphaAnimator.current * generalAlpha * horizontalLinesAlpha) + } + + if drawAxisX { + context.setLineWidth(axisXWidth) + context.setStrokeColor(axisXColor.withAlphaComponent(axisXColor.alphaValue * horizontalLinesAlpha * generalAlpha).cgColor) + + let lineSegments: [CGPoint] = [CGPoint(x: chartFrame.minX, y: chartFrame.maxY.roundedUpToPixelGrid()), + CGPoint(x: chartFrame.maxX, y: chartFrame.maxY.roundedUpToPixelGrid())] + + context.strokeLineSegments(between: lineSegments) + } + } + + drawVerticalLabels(verticalLabelsAndLines, attributes: [.foregroundColor: labelsColor.withAlphaComponent(labelColorAlpha * generalAlpha), + .font: labelsFont]) + for animatedLabesAndLines in animatedVerticalLabelsAndLines { + drawVerticalLabels(animatedLabesAndLines.labels, + attributes: [.foregroundColor: labelsColor.withAlphaComponent(animatedLabesAndLines.alphaAnimator.current * labelColorAlpha * generalAlpha), + .font: labelsFont]) + } + } +} diff --git a/submodules/Charts/Sources/Helpers/AnimationController.swift b/submodules/Charts/Sources/Helpers/AnimationController.swift new file mode 100644 index 0000000000..6df8d17f76 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/AnimationController.swift @@ -0,0 +1,178 @@ +// +// RangeAnimatedContainer.swift +// GraphTest +// +// Created by Andrei Salavei on 3/12/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +protocol Animatable { + static func valueBetween(start: Self, end: Self, offset: Double) -> Self +} + +enum TimeFunction { + case linear + case easeOut + case easeIn + + func profress(time: TimeInterval, duration: TimeInterval) -> TimeInterval { + switch self { + case .linear: + return time / duration + case .easeIn: + return (pow(2, 10 * (time / duration - 1)) - 0.0009765625) * 1.0009775171065499 + + case .easeOut: + return (-pow(2, -10 * time / duration)) + 1 * 1.0009775171065499 + } + } +} + +class AnimationController { + + private(set) var isAnimating: Bool = false + private(set) var animationDuration: TimeInterval = 0.0 + private(set) var currentTime: TimeInterval = 0.0 + + private(set) var start: AnimatableObject + private(set) var end: AnimatableObject + private(set) var current: AnimatableObject + + var timeFunction: TimeFunction = .linear + + var refreshClosure: (() -> Void)? +// var updateClosure: ((AnimatableObject) -> Void)? + var completionClosure: (() -> Void)? + + init(current: AnimatableObject, refreshClosure: (() -> Void)?) { + self.current = current + self.start = current + self.end = current + self.refreshClosure = refreshClosure + } + + func animate(to: AnimatableObject, duration: TimeInterval, timeFunction: TimeFunction = .linear) { + self.timeFunction = timeFunction + currentTime = 0 + animationDuration = duration + if animationDuration > 0 { + start = current + end = to + isAnimating = true + DisplayLinkService.shared.add(listner: self) + } else { + start = to + end = to + current = to + isAnimating = false + DisplayLinkService.shared.remove(listner: self) + } + refreshClosure?() + } + + func set(current: AnimatableObject) { + self.start = current + self.end = current + self.current = current + + animationDuration = 0.0 + currentTime = 0.0 +// updateClosure?(current) + refreshClosure?() + if isAnimating { + isAnimating = false + DisplayLinkService.shared.remove(listner: self) + } + } +} + +extension AnimationController: DisplayLinkListner { + func update(delta: TimeInterval) { + guard isAnimating else { + DisplayLinkService.shared.remove(listner: self) + return + } + + currentTime += delta + if currentTime > animationDuration || animationDuration <= 0 { + start = end + current = end + isAnimating = false + animationDuration = 0.0 + currentTime = 0.0 +// updateClosure?(end) + completionClosure?() + refreshClosure?() + DisplayLinkService.shared.remove(listner: self) + } else { + let offset = timeFunction.profress(time: currentTime, duration: animationDuration) + current = AnimatableObject.valueBetween(start: start, end: end, offset: offset) +// updateClosure?(current) + refreshClosure?() + } + } +} + +extension ClosedRange: Animatable where Bound: BinaryFloatingPoint { + static func valueBetween(start: ClosedRange, end: ClosedRange, offset: Double) -> ClosedRange { + let castedOffset = Bound(offset) + return ClosedRange(uncheckedBounds: (lower: start.lowerBound + (end.lowerBound - start.lowerBound) * castedOffset, + upper: start.upperBound + (end.upperBound - start.upperBound) * castedOffset)) + } +} + +extension CGFloat: Animatable { + static func valueBetween(start: CGFloat, end: CGFloat, offset: Double) -> CGFloat { + return start + (end - start) * CGFloat(offset) + } +} + +extension Double: Animatable { + static func valueBetween(start: Double, end: Double, offset: Double) -> Double { + return start + (end - start) * Double(offset) + } +} + +extension Int: Animatable { + static func valueBetween(start: Int, end: Int, offset: Double) -> Int { + return start + Int(Double(end - start) * offset) + } +} + +extension CGPoint: Animatable { + static func valueBetween(start: CGPoint, end: CGPoint, offset: Double) -> CGPoint { + return CGPoint(x: start.x + (end.x - start.x) * CGFloat(offset), + y: start.y + (end.y - start.y) * CGFloat(offset)) + } +} + +extension CGRect: Animatable { + static func valueBetween(start: CGRect, end: CGRect, offset: Double) -> CGRect { + return CGRect(x: start.origin.x + (end.origin.x - start.origin.x) * CGFloat(offset), + y: start.origin.y + (end.origin.y - start.origin.y) * CGFloat(offset), + width: start.width + (end.width - start.width) * CGFloat(offset), + height: start.height + (end.height - start.height) * CGFloat(offset)) + } +} + +struct UIColorContainer: Animatable { + var color: UIColor + + static func valueBetween(start: UIColorContainer, end: UIColorContainer, offset: Double) -> UIColorContainer { + return UIColorContainer(color: UIColor.valueBetween(start: start.color, end: end.color, offset: offset)) + } +} + +extension UIColor { + static func valueBetween(start: UIColor, end: UIColor, offset: Double) -> UIColor { + let offsetF = CGFloat(offset) + let startCIColor = CIColor(color: start) + let endCIColor = CIColor(color: end) + return UIColor(red: startCIColor.red + (endCIColor.red - startCIColor.red) * offsetF, + green: startCIColor.green + (endCIColor.green - startCIColor.green) * offsetF, + blue: startCIColor.blue + (endCIColor.blue - startCIColor.blue) * offsetF, + alpha: startCIColor.alpha + (endCIColor.alpha - startCIColor.alpha) * offsetF) + } +} diff --git a/submodules/Charts/Sources/Helpers/Array+Utils.swift b/submodules/Charts/Sources/Helpers/Array+Utils.swift new file mode 100644 index 0000000000..539a559756 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/Array+Utils.swift @@ -0,0 +1,18 @@ +// +// Array+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension Array { + func safeElement(at index: Int) -> Element? { + if index >= 0 && index < count { + return self[index] + } + return nil + } +} diff --git a/submodules/Charts/Sources/Helpers/CGFloat.swift b/submodules/Charts/Sources/Helpers/CGFloat.swift new file mode 100644 index 0000000000..7bde39b84f --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CGFloat.swift @@ -0,0 +1,17 @@ +// +// CGFloat.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let screenScale: CGFloat = UIScreen.main.scale + +extension CGFloat { + func roundedUpToPixelGrid() -> CGFloat { + return (self * screenScale).rounded(.up) / screenScale + } +} diff --git a/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift b/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift new file mode 100644 index 0000000000..b5bbd06da4 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CGPoint+Extensions.swift @@ -0,0 +1,219 @@ +// +// CGPoint+Extensions.swift +// GraphTest +// +// Created by Andrei Salavei on 4/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension CGPoint { + public init(vector: CGVector) { + self.init(x: vector.dx, y: vector.dy) + } + + + public init(angle: CGFloat) { + self.init(x: cos(angle), y: sin(angle)) + } + + + public mutating func offset(dx: CGFloat, dy: CGFloat) -> CGPoint { + x += dx + y += dy + return self + } + + public func length() -> CGFloat { + return sqrt(x*x + y*y) + } + + public func lengthSquared() -> CGFloat { + return x*x + y*y + } + + func normalized() -> CGPoint { + let len = length() + return len>0 ? self / len : CGPoint.zero + } + + public mutating func normalize() -> CGPoint { + self = normalized() + return self + } + + public func distanceTo(_ point: CGPoint) -> CGFloat { + return (self - point).length() + } + + public var angle: CGFloat { + return atan2(y, x) + } + + public var cgSize: CGSize { + return CGSize(width: x, height: y) + } + + func rotate(origin: CGPoint, angle: CGFloat) -> CGPoint { + let point = self - origin + let s = sin(angle) + let c = cos(angle) + return CGPoint(x: c * point.x - s * point.y, + y: s * point.x + c * point.y) + origin + } +} + +extension CGSize { + public var cgPoint: CGPoint { + return CGPoint(x: width, y: height) + } + + public init(point: CGPoint) { + self.init(width: point.x, height: point.y) + } +} + +public func + (left: CGPoint, right: CGPoint) -> CGPoint { + return CGPoint(x: left.x + right.x, y: left.y + right.y) +} + +public func += (left: inout CGPoint, right: CGPoint) { + left = left + right +} + +public func + (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x + right.dx, y: left.y + right.dy) +} + +public func += (left: inout CGPoint, right: CGVector) { + left = left + right +} + +public func - (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x - right.x, y: left.y - right.y) } +public func - (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width - right.width, height: left.height - right.height) } +public func - (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width - right.x, height: left.height - right.x) } +public func - (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x - right.width, y: left.y - right.height) } + +public func -= (left: inout CGPoint, right: CGPoint) { + left = left - right +} + +public func - (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x - right.dx, y: left.y - right.dy) +} + +public func -= (left: inout CGPoint, right: CGVector) { + left = left - right +} + +public func *= (left: inout CGPoint, right: CGPoint) { + left = left * right +} + +public func * (point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x * scalar, y: point.y * scalar) } +public func * (point: CGSize, scalar: CGFloat) -> CGSize { return CGSize(width: point.width * scalar, height: point.height * scalar) } + +public func *= (point: inout CGPoint, scalar: CGFloat) { point = point * scalar } + +public func * (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x * right.dx, y: left.y * right.dy) +} + +public func *= (left: inout CGPoint, right: CGVector) { + left = left * right +} + +public func / (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x / right.x, y: left.y / right.y) } +public func / (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width / right.width, height: left.height / right.height) } +public func / (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x / right.width, y: left.y / right.height) } +public func / (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width / right.x, height: left.height / right.y) } +public func /= (left: inout CGPoint, right: CGPoint) { left = left / right } +public func /= (left: inout CGSize, right: CGSize) { left = left / right } +public func /= (left: inout CGSize, right: CGPoint) { left = left / right } +public func /= (left: inout CGPoint, right: CGSize) { left = left / right } + + +public func / (point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x / scalar, y: point.y / scalar) } +public func / (point: CGSize, scalar: CGFloat) -> CGSize { return CGSize(width: point.width / scalar, height: point.height / scalar) } + +public func /= (point: inout CGPoint, scalar: CGFloat) { + point = point / scalar +} + +public func / (left: CGPoint, right: CGVector) -> CGPoint { + return CGPoint(x: left.x / right.dx, y: left.y / right.dy) +} + +public func / (left: CGSize, right: CGVector) -> CGSize { + return CGSize(width: left.width / right.dx, height: left.height / right.dy) +} + +public func /= (left: inout CGPoint, right: CGVector) { + left = left / right +} + +public func * (left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x * right.x, y: left.y * right.y) } +public func * (left: CGPoint, right: CGSize) -> CGPoint { return CGPoint(x: left.x * right.width, y: left.y * right.height) } +public func *= (left: inout CGPoint, right: CGSize) { left = left * right } +public func * (left: CGSize, right: CGSize) -> CGSize { return CGSize(width: left.width * right.width, height: left.height * right.height) } +public func *= (left: inout CGSize, right: CGSize) { left = left * right } +public func * (left: CGSize, right: CGPoint) -> CGSize { return CGSize(width: left.width * right.x, height: left.height * right.y) } +public func *= (left: inout CGSize, right: CGPoint) { left = left * right } + + +public func lerp(start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { + return start + (end - start) * t +} + +public func abs(_ point: CGPoint) -> CGPoint { + return CGPoint(x: abs(point.x), y: abs(point.y)) +} + +extension CGSize { + var isValid: Bool { + return width > 0 && height > 0 && width != .infinity && height != .infinity && width != .nan && height != .nan + } + + var ratio: CGFloat { + return width / height + } +} + + +extension CGRect { + static var identity: CGRect { + return CGRect(x: 0, y: 0, width: 1, height: 1) + } + + var center: CGPoint { + return origin + size.cgPoint / 2 + } + + var rounded: CGRect { + return CGRect(x: origin.x.rounded(), + y: origin.y.rounded(), + width: width.rounded(.up), + height: height.rounded(.up)) + } + + var mirroredVertically: CGRect { + return CGRect(x: origin.x, + y: 1.0 - (origin.y + height), + width: width, + height: height) + } +} + +extension CGAffineTransform { + func inverted(with size: CGSize) -> CGAffineTransform { + var transform = self + let transformedSize = CGRect(origin: .zero, size: size).applying(transform).size + transform.tx /= transformedSize.width; + transform.ty /= transformedSize.height; + transform = transform.inverted() + transform.tx *= transformedSize.width; + transform.ty *= transformedSize.height; + return transform + } +} diff --git a/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift b/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift new file mode 100644 index 0000000000..236d6c8a38 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/ClosedRange+Utils.swift @@ -0,0 +1,15 @@ +// +// ClosedRange+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension ClosedRange where Bound: Numeric { + var distance: Bound { + return upperBound - lowerBound + } +} diff --git a/submodules/Charts/Sources/Helpers/CustomNavigationController.swift b/submodules/Charts/Sources/Helpers/CustomNavigationController.swift new file mode 100644 index 0000000000..977244dfcc --- /dev/null +++ b/submodules/Charts/Sources/Helpers/CustomNavigationController.swift @@ -0,0 +1,19 @@ +// +// CustomNavigationController.swift +// GraphTest +// +// Created by Andrew Solovey on 15/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +class CustomNavigationController: UINavigationController { + override var preferredStatusBarStyle: UIStatusBarStyle { + return topViewController?.preferredStatusBarStyle ?? .default + } + + override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { + return topViewController?.preferredStatusBarUpdateAnimation ?? .fade + } +} diff --git a/submodules/Charts/Sources/Helpers/DisplayLinkService.swift b/submodules/Charts/Sources/Helpers/DisplayLinkService.swift new file mode 100644 index 0000000000..2c91471c39 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/DisplayLinkService.swift @@ -0,0 +1,114 @@ +// +// DisplayLinkService.swift +// GraphTest +// +// Created by Andrei Salavei on 4/7/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit +import CoreGraphics + +public protocol DisplayLinkListner: class { + func update(delta: TimeInterval) +} + +// DispatchSource mares refreshes more accurate +class DisplayLinkService { + let listners = NSHashTable.weakObjects() + static let shared = DisplayLinkService() + + public func add(listner: DisplayLinkListner) { + listners.add(listner) + startDisplayLink() + } + + public func remove(listner: DisplayLinkListner) { + listners.remove(listner) + + if listners.count == 0 { + stopDisplayLink() + } + } + +// private init() { +// displayLink.add(to: .main, forMode: .common) +// displayLink.preferredFramesPerSecond = 60 +// displayLink.isPaused = true +// } +// +// // MARK: - Display Link +// private lazy var displayLink: CADisplayLink! = { CADisplayLink(target: self, selector: #selector(displayLinkDidFire)) } () +// private var previousTickTime = 0.0 +// +// private func startDisplayLink() { +// guard displayLink.isPaused else { +// return +// } +// previousTickTime = CACurrentMediaTime() +// displayLink.isPaused = false +// } +// +// @objc private func displayLinkDidFire(_ displayLink: CADisplayLink) { +// let currentTime = CACurrentMediaTime() +// let delta = currentTime - previousTickTime +// previousTickTime = currentTime +// let allListners = listners.allObjects +// var hasListners = false +// for listner in allListners { +// (listner as! DisplayLinkListner).update(delta: delta) +// hasListners = true +// } +// +// if !hasListners { +// stopDisplayLink() +// } +// } +// +// private func stopDisplayLink() { +// displayLink.isPaused = true +// } + + private init() { + dispatchSourceTimer.schedule(deadline: .now() + 1.0 / 60, repeating: 1.0 / 60) + dispatchSourceTimer.setEventHandler { + DispatchQueue.main.sync { + self.fire() + } + } + } + + private var dispatchSourceTimer = DispatchSource.makeTimerSource(flags: [], queue: .global(qos: .userInteractive)) + private var dispatchSourceTimerStarted: Bool = false + private var previousTickTime = 0.0 + + private func startDisplayLink() { + guard !dispatchSourceTimerStarted else { return } + dispatchSourceTimerStarted = true + previousTickTime = CACurrentMediaTime() + dispatchSourceTimer.resume() + } + + private func stopDisplayLink() { + guard dispatchSourceTimerStarted else { return } + dispatchSourceTimerStarted = false + dispatchSourceTimer.suspend() + } + + public func fire() { + let currentTime = CACurrentMediaTime() + + let delta = currentTime - previousTickTime + previousTickTime = currentTime + let allListners = listners.allObjects + var hasListners = false + for listner in allListners { + (listner as! DisplayLinkListner).update(delta: delta) + hasListners = true + } + + if !hasListners { + stopDisplayLink() + } + } +} diff --git a/submodules/Charts/Sources/Helpers/GlobalHelpers.swift b/submodules/Charts/Sources/Helpers/GlobalHelpers.swift new file mode 100644 index 0000000000..3f5c488ff9 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/GlobalHelpers.swift @@ -0,0 +1,12 @@ +// +// GlobalHelpers.swift +// TrackingRecorder +// +// Created by Andrew Solovey on 07.09.2018. +// Copyright © 2018 Andrew Solovey. All rights reserved. +// + +public func crop(_ lower: Type, _ val: Type, _ upper: Type) -> Type where Type : Comparable { + assert(lower < upper, "Invalid lover and upper values") + return max(lower, min(upper, val)) +} diff --git a/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift b/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift new file mode 100644 index 0000000000..1254d44249 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/NumberFormatter+Utils.swift @@ -0,0 +1,19 @@ +// +// NumberFormatter+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/12/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension NumberFormatter { + func string(from value: CGFloat) -> String { + return string(from: Double(value)) + } + + func string(from value: Double) -> String { + return string(from: NSNumber(value: Double(value))) ?? "" + } +} diff --git a/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift b/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift new file mode 100644 index 0000000000..03e33e6524 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/OnePixelConstraint.swift @@ -0,0 +1,17 @@ +// +// OnePixelConstraint.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +public class OnePixelConstrain: NSLayoutConstraint { + public override func awakeFromNib() { + super.awakeFromNib() + + constant = UIView.oneDevicePixel + } +} diff --git a/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift b/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift new file mode 100644 index 0000000000..db067f8a95 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/ScalesNumberFormatter.swift @@ -0,0 +1,32 @@ +// +// ScalesNumberFormatter.swift +// GraphTest +// +// Created by Andrei Salavei on 4/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +private let milionsScale = "M" +private let thousandsScale = "K" + +class ScalesNumberFormatter: NumberFormatter { + override func string(from number: NSNumber) -> String? { + let value = number.doubleValue + let pow = log10(value) + if pow >= 6 { + guard let string = super.string(from: NSNumber(value: value / 1_000_000)) else { + return nil + } + return string + milionsScale + } else if pow >= 4 { + guard let string = super.string(from: NSNumber(value: value / 1_000)) else { + return nil + } + return string + thousandsScale + } else { + return super.string(from: number) + } + } +} diff --git a/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift b/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift new file mode 100644 index 0000000000..204b1e861a --- /dev/null +++ b/submodules/Charts/Sources/Helpers/TimeInterval+Utils.swift @@ -0,0 +1,27 @@ +// +// TimeInterval+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension TimeInterval { + static let minute: TimeInterval = 60 + static let hour: TimeInterval = 60 * 60 + static let day: TimeInterval = 60 * 60 * 24 + static let osXDuration: TimeInterval = 0.25 + static let expandAnimationDuration: TimeInterval = 0.4 + static var animationDurationMultipler: Double = 1.0 + + static var defaultDuration: TimeInterval { + return innerDefaultDuration * animationDurationMultipler + } + private static var innerDefaultDuration: TimeInterval = osXDuration + + static func setDefaultSuration(_ duration: TimeInterval) { + innerDefaultDuration = duration + } +} diff --git a/submodules/Charts/Sources/Helpers/TimeZone.swift b/submodules/Charts/Sources/Helpers/TimeZone.swift new file mode 100644 index 0000000000..40ba9ab8f5 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/TimeZone.swift @@ -0,0 +1,36 @@ +// +// TimeZone.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import Foundation + +extension TimeZone { + static let utc = TimeZone(secondsFromGMT: 0)! +} + +extension Locale { + static let posix = Locale(identifier: "en_US_POSIX") +} + +extension Calendar { + static let utc: Calendar = { + var calendar = Calendar.current + calendar.locale = Locale.posix + calendar.timeZone = TimeZone.utc + return calendar + }() +} + +extension DateFormatter { + static func utc(format: String = "") -> DateFormatter { + let formatter = DateFormatter() + formatter.calendar = Calendar.utc + formatter.dateFormat = format + formatter.timeZone = TimeZone.utc + return formatter + } +} diff --git a/submodules/Charts/Sources/Helpers/UIColor+Utils.swift b/submodules/Charts/Sources/Helpers/UIColor+Utils.swift new file mode 100644 index 0000000000..0a70421d5e --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIColor+Utils.swift @@ -0,0 +1,64 @@ +// +// UIColor+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 3/11/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIColor { + public convenience init?(hexString: String) { + let r, g, b, a: CGFloat + + if hexString.hasPrefix("#") { + let start = hexString.index(hexString.startIndex, offsetBy: 1) + let hexColor = String(hexString[start...]) + + if hexColor.count == 8 { + let scanner = Scanner(string: hexColor) + var hexNumber: UInt64 = 0 + + if scanner.scanHexInt64(&hexNumber) { + r = CGFloat((hexNumber & 0xff000000) >> 24) / 255 + g = CGFloat((hexNumber & 0x00ff0000) >> 16) / 255 + b = CGFloat((hexNumber & 0x0000ff00) >> 8) / 255 + a = CGFloat(hexNumber & 0x000000ff) / 255 + + self.init(red: r, green: g, blue: b, alpha: a) + return + } + } else if hexColor.count == 6 { + let scanner = Scanner(string: hexColor) + var hexNumber: UInt64 = 0 + + if scanner.scanHexInt64(&hexNumber) { + r = CGFloat((hexNumber & 0xff0000) >> 16) / 255 + g = CGFloat((hexNumber & 0x00ff00) >> 8) / 255 + b = CGFloat((hexNumber & 0x0000ff) >> 0) / 255 + + self.init(red: r, green: g, blue: b, alpha: 1.0) + return + } + } + } + return nil + } + + func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage { + if #available(iOS 10.0, *) { + return UIGraphicsImageRenderer(size: size).image { rendererContext in + self.setFill() + rendererContext.fill(CGRect(origin: .zero, size: size)) + } + } else { + return UIImage() + } + } + + var redValue: CGFloat{ return CIColor(color: self).red } + var greenValue: CGFloat{ return CIColor(color: self).green } + var blueValue: CGFloat{ return CIColor(color: self).blue } + var alphaValue: CGFloat{ return CIColor(color: self).alpha } +} diff --git a/submodules/Charts/Sources/Helpers/UIImage+Utils.swift b/submodules/Charts/Sources/Helpers/UIImage+Utils.swift new file mode 100644 index 0000000000..50964025c2 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIImage+Utils.swift @@ -0,0 +1,28 @@ +// +// UIImage+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/8/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIImage { + static let arrowRight = UIImage(bundleImageName: "Chart/arrow_right") + static let arrowLeft = UIImage(bundleImageName: "Chart/arrow_left") + + public convenience init?(color: UIColor, size: CGSize = CGSize(width: 1, height: 1)) { + let rect = CGRect(origin: .zero, size: size) + UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0) + color.setFill() + UIRectFill(rect) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + guard let cgImage = image?.cgImage else { return nil } + self.init(cgImage: cgImage) + } + + +} diff --git a/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift b/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift new file mode 100644 index 0000000000..608f25a114 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIImageView+Utils.swift @@ -0,0 +1,24 @@ +// +// UIImageView+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIImageView { + func setImage(_ image: UIImage?, animated: Bool) { + if self.image != image { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionImageFade") + } + self.image = image + } + } +} diff --git a/submodules/Charts/Sources/Helpers/UILabel+Utils.swift b/submodules/Charts/Sources/Helpers/UILabel+Utils.swift new file mode 100644 index 0000000000..6c41c73fd9 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UILabel+Utils.swift @@ -0,0 +1,37 @@ +// +// UILabel+Utils.swift +// GraphTest +// +// Created by Andrei Salavei on 4/9/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UILabel { + func setTextColor(_ color: UIColor, animated: Bool) { + if self.textColor != color { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionColorFade") + } + self.textColor = color + } + } + + func setText(_ title: String?, animated: Bool) { + if self.text != title { + if animated { + let animation = CATransition() + animation.timingFunction = CAMediaTimingFunction.init(name: .linear) + animation.type = .fade + animation.duration = .defaultDuration + self.layer.add(animation, forKey: "kCATransitionTextFade") + } + self.text = title + } + } +} diff --git a/submodules/Charts/Sources/Helpers/UIView+Extensions.swift b/submodules/Charts/Sources/Helpers/UIView+Extensions.swift new file mode 100644 index 0000000000..bba2d1f886 --- /dev/null +++ b/submodules/Charts/Sources/Helpers/UIView+Extensions.swift @@ -0,0 +1,57 @@ +// +// UIView+Extensions.swift +// GraphTest +// +// Created by Andrei Salavei on 4/10/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +extension UIView { + static let oneDevicePixel: CGFloat = (1.0 / max(2, min(1, UIScreen.main.scale))) +} + +// MARK: UIView+Animation +public extension UIView { + func bringToFront() { + superview?.bringSubviewToFront(self) + } + + func layoutIfNeeded(animated: Bool) { + UIView.perform(animated: animated) { + self.layoutIfNeeded() + } + } + + func setVisible(_ visible: Bool, animated: Bool) { + let updatedAlpha: CGFloat = visible ? 1 : 0 + if self.alpha != updatedAlpha { + UIView.perform(animated: animated) { + self.alpha = updatedAlpha + } + } + } + + static func perform(animated: Bool, animations: @escaping () -> Void) { + perform(animated: animated, animations: animations, completion: { _ in }) + } + + static func perform(animated: Bool, animations: @escaping () -> Void, completion: @escaping (Bool) -> Void) { + if animated { + + UIView.animate(withDuration: .defaultDuration, delay: 0, animations: animations, completion: completion) + } else { + animations() + completion(true) + } + } + + var isVisibleInWindow: Bool { + guard let windowBounds = window?.bounds else { + return false + } + let frame = convert(bounds, to: nil) + return frame.intersects(windowBounds) + } +} diff --git a/submodules/Charts/Sources/Models/ChartLineData.swift b/submodules/Charts/Sources/Models/ChartLineData.swift new file mode 100644 index 0000000000..79813a2a35 --- /dev/null +++ b/submodules/Charts/Sources/Models/ChartLineData.swift @@ -0,0 +1,76 @@ +// +// ChartLineData.swift +// GraphTest +// +// Created by Andrei Salavei on 3/13/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct ChartLineData { + var title: String + var color: UIColor + var width: CGFloat? + var points: [CGPoint] +} + +extension ChartLineData { + static func horizontalRange(lines: [ChartLineData]) -> ClosedRange? { + guard let firstPoint = lines.first?.points.first else { return nil } + var hMin: CGFloat = firstPoint.x + var hMax: CGFloat = firstPoint.x + + for line in lines { + if let first = line.points.first, + let last = line.points.last { + hMin = min(hMin, first.x) + hMax = max(hMax, last.x) + } + } + + return hMin...hMax + } + + static func verticalRange(lines: [ChartLineData], calculatingRange: ClosedRange? = nil, addBounds: Bool = false) -> ClosedRange? { + if let calculatingRange = calculatingRange { + guard let initalStart = lines.first?.points.first(where: { $0.x > calculatingRange.lowerBound && + $0.x < calculatingRange.upperBound }) else { return nil } + var vMin: CGFloat = initalStart.y + var vMax: CGFloat = initalStart.y + for line in lines { + if var index = line.points.firstIndex(where: { $0.x > calculatingRange.lowerBound }) { + if addBounds { + index = max(0, index - 1) + } + while index < line.points.count { + let point = line.points[index] + if point.x < calculatingRange.upperBound { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } else if addBounds { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + break + } else { + break + } + index += 1 + } + } + } + return vMin...vMax + } else { + guard let firstPoint = lines.first?.points.first else { return nil } + var vMin: CGFloat = firstPoint.y + var vMax: CGFloat = firstPoint.y + for line in lines { + for point in line.points { + vMin = min(vMin, point.y) + vMax = max(vMax, point.y) + } + } + return vMin...vMax + } + } +} diff --git a/submodules/Charts/Sources/Models/ColorMode.swift b/submodules/Charts/Sources/Models/ColorMode.swift new file mode 100644 index 0000000000..f0de7b52ae --- /dev/null +++ b/submodules/Charts/Sources/Models/ColorMode.swift @@ -0,0 +1,175 @@ +// +// ColorMode.swift +// GraphTest +// +// Created by Andrew Solovey on 15/03/2019. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit +import AppBundle + +protocol ColorModeContainer { + func apply(colorMode: ColorMode, animated: Bool) +} + +enum ColorMode { + case day + case night +} + +extension ColorMode { + var chartTitleColor: UIColor { // Текст с датой на чарте + switch self { + case .day: return .black + case .night: return .white + } + } + + var actionButtonColor: UIColor { // Кнопка Zoom Out/ Смена режима день/ночь + switch self { + case .day: return UIColor(red: 53/255.0, green: 120/255.0, blue: 246/255.0, alpha: 1.0) + case .night: return UIColor(red: 84/255.0, green: 164/255.0, blue: 247/255.0, alpha: 1.0) + } + } + + var tableBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 239/255.0, green: 239/255.0, blue: 244/255.0, alpha: 1.0) + case .night: return UIColor(red: 24/255.0, green: 34/255.0, blue: 45/255.0, alpha: 1.0) + } + } + + var chartBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + case .night: return UIColor(red: 34/255.0, green: 47/255.0, blue: 63/255.0, alpha: 1.0) + } + } + + var sectionTitleColor: UIColor { + switch self { + case .day: return UIColor(red: 109/255.0, green: 109/255.0, blue: 114/255.0, alpha: 1.0) + case .night: return UIColor(red: 133/255.0, green: 150/255.0, blue: 171/255.0, alpha: 1.0) + } + } + + var tableSeparatorColor: UIColor { + switch self { + case .day: return UIColor(red: 200/255.0, green: 199/255.0, blue: 204/255.0, alpha: 1.0) + case .night: return UIColor(red: 18/255.0, green: 26/255.0, blue: 35/255.0, alpha: 1.0) + } + } + + var chartLabelsColor: UIColor { + switch self { + case .day: return UIColor(red: 37/255.0, green: 37/255.0, blue: 41/255.0, alpha: 0.5) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.6) + } + } + + var chartHelperLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 24/255.0, green: 45/255.0, blue: 59/255.0, alpha: 0.1) + case .night: return UIColor(red: 133/255.0, green: 150/255.0, blue: 171/255.0, alpha: 0.20) + } + } + + var chartStrongLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 24/255.0, green: 45/255.0, blue: 59/255.0, alpha: 0.35) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.45) + } + } + + var barChartStrongLinesColor: UIColor { + switch self { + case .day: return UIColor(red: 37/255.0, green: 37/255.0, blue: 41/255.0, alpha: 0.2) + case .night: return UIColor(red: 186/255.0, green: 204/255.0, blue: 225/255.0, alpha: 0.45) + } + } + + var chartDetailsTextColor: UIColor { + switch self { + case .day: return UIColor(red: 109/255.0, green: 109/255.0, blue: 114/255.0, alpha: 1.0) + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var chartDetailsArrowColor: UIColor { + switch self { + case .day: return UIColor(red: 197/255.0, green: 199/255.0, blue: 205/255.0, alpha: 1.0) + case .night: return UIColor(red: 76/255.0, green: 84/255.0, blue: 96/255.0, alpha: 1.0) + } + } + + var chartDetailsViewColor: UIColor { + switch self { + case .day: return UIColor(red: 245/255.0, green: 245/255.0, blue: 251/255.0, alpha: 1.0) + case .night: return UIColor(red: 25/255.0, green: 35/255.0, blue: 47/255.0, alpha: 1.0) + } + } + + var descriptionChatNameColor: UIColor { + switch self { + case .day: return .black + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var descriptionActionColor: UIColor { + switch self { + case .day: return UIColor(red: 1/255.0, green: 125/255.0, blue: 229/255.0, alpha: 1.0) + case .night: return UIColor(red: 24/255.0, green: 145/255.0, blue: 255/255.0, alpha: 1.0) + } + } + + var rangeViewBackgroundColor: UIColor { + switch self { + case .day: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + case .night: return UIColor(red: 34/255.0, green: 47/255.0, blue: 63/255.0, alpha: 1.0) + } + } + + var rangeViewFrameColor: UIColor { + switch self { + case .day: return UIColor(red: 202/255.0, green: 212/255.0, blue: 222/255.0, alpha: 1.0) + case .night: return UIColor(red: 53/255.0, green: 70/255.0, blue: 89/255.0, alpha: 1.0) + } + } + + var rangeViewTintColor: UIColor { + switch self { + case .day: return UIColor(red: 239/255.0, green: 239/255.0, blue: 244/255.0, alpha: 0.5) + case .night: return UIColor(red: 24/255.0, green: 34/255.0, blue: 45/255.0, alpha: 0.5) + } + } + + var rangeViewMarkerColor: UIColor { + switch self { + case .day: return UIColor.white + case .night: return UIColor.white + } + } + + var statusBarStyle: UIStatusBarStyle { + switch self { + case .day: return .default + case .night: return .lightContent + } + } + + var viewTintColor: UIColor { + switch self { + case .day: return .black + case .night: return UIColor(red: 254/255.0, green: 254/255.0, blue: 254/255.0, alpha: 1.0) + } + } + + var rangeCropImage: UIImage? { + switch self { + case .day: return UIImage(bundleImageName: "Chart/selection_frame_light") + case .night: return UIImage(bundleImageName: "Chart/selection_frame_dark") + } + } +} diff --git a/submodules/Charts/Sources/Models/LinesChartLabel.swift b/submodules/Charts/Sources/Models/LinesChartLabel.swift new file mode 100644 index 0000000000..6ace8c2c65 --- /dev/null +++ b/submodules/Charts/Sources/Models/LinesChartLabel.swift @@ -0,0 +1,25 @@ +// +// LinesChartLabel.swift +// GraphTest +// +// Created by Andrei Salavei on 3/18/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct LinesChartLabel: Hashable { + let value: CGFloat + let text: String +} + +class AnimatedLinesChartLabels { + var labels: [LinesChartLabel] + var isAppearing: Bool = false + let alphaAnimator: AnimationController + + init(labels: [LinesChartLabel], alphaAnimator: AnimationController) { + self.labels = labels + self.alphaAnimator = alphaAnimator + } +} diff --git a/submodules/Charts/Sources/Models/LinesSelectionLabel.swift b/submodules/Charts/Sources/Models/LinesSelectionLabel.swift new file mode 100644 index 0000000000..0fd7142eda --- /dev/null +++ b/submodules/Charts/Sources/Models/LinesSelectionLabel.swift @@ -0,0 +1,15 @@ +// +// LinesSelectionLabel.swift +// GraphTest +// +// Created by Andrei Salavei on 3/18/19. +// Copyright © 2019 Andrei Salavei. All rights reserved. +// + +import UIKit + +struct LinesSelectionLabel { + let coordinate: CGPoint + let valueText: String + let color: UIColor +} diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index f2049711c5..4874490784 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -22,10 +22,6 @@ import AppBundle import LocalizedPeerData import TelegramIntents -public func useSpecialTabBarIcons() -> Bool { - return (Date(timeIntervalSince1970: 1545642000)...Date(timeIntervalSince1970: 1546387200)).contains(Date()) -} - private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool { if searchNode.expansionProgress > 0.0 && searchNode.expansionProgress < 1.0 { let scrollToItem: ListViewScrollToItem @@ -178,8 +174,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, self.tabBarItem.title = self.presentationData.strings.DialogList_Title let icon: UIImage? - if (useSpecialTabBarIcons()) { - icon = UIImage(bundleImageName: "Chat List/Tabs/NY/IconChats") + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconChats") } else { icon = UIImage(bundleImageName: "Chat List/Tabs/IconChats") } diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 22e250ef4a..af2a6d1b88 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -715,7 +715,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo return (views, local) } } - |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> in + |> mapToSignal { viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId: (Int32, Bool)]), NoError> in return context.account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in var unread: [PeerId: (Int32, Bool)] = [:] for peerView in viewsAndPeers.0 { @@ -804,8 +804,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo ) } - return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get(), searchStatePromise.get()) - |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData, searchState -> ([ChatListSearchEntry], Bool)? in + let resolvedMessage = .single(nil) + |> then(context.sharedContext.resolveUrl(account: context.account, url: query) + |> mapToSignal { resolvedUrl -> Signal in + if case let .channelMessage(peerId, messageId) = resolvedUrl { + return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId) + } else { + return .single(nil) + } + }) + + return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get(), searchStatePromise.get(), resolvedMessage) + |> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData, searchState, resolvedMessage -> ([ChatListSearchEntry], Bool)? in var entries: [ChatListSearchEntry] = [] let isSearching = foundRemotePeers.2 || foundRemoteMessages.1 var index = 0 @@ -938,6 +948,17 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } } + if let message = resolvedMessage { + var peer = RenderedPeer(message: message) + if let group = message.peers[message.id.peerId] as? TelegramGroup, let migrationReference = group.migrationReference { + if let channelPeer = message.peers[migrationReference.peerId] { + peer = RenderedPeer(peer: channelPeer) + } + } + entries.append(.message(message, peer, nil, presentationData)) + index += 1 + } + if !foundRemotePeers.2 { index = 0 for message in foundRemoteMessages.0.0 { diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index 7dcfc4b716..b65dfabfec 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -105,7 +105,12 @@ public class ContactsController: ViewController { self.title = self.presentationData.strings.Contacts_Title self.tabBarItem.title = self.presentationData.strings.Contacts_Title - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconContacts") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconContacts") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconContacts") + } self.tabBarItem.image = icon self.tabBarItem.selectedImage = icon diff --git a/submodules/Display/Display/TabBarNode.swift b/submodules/Display/Display/TabBarNode.swift index f83a6b1289..9301512ec1 100644 --- a/submodules/Display/Display/TabBarNode.swift +++ b/submodules/Display/Display/TabBarNode.swift @@ -442,7 +442,7 @@ class TabBarNode: ASDisplayNode { if horizontal { backgroundFrame = CGRect(origin: CGPoint(x: originX + 15.0, y: 3.0), size: backgroundSize) } else { - let contentWidth = node.contentWidth ?? node.frame.width + let contentWidth: CGFloat = 25.0 //node.contentWidth ?? node.frame.width backgroundFrame = CGRect(origin: CGPoint(x: floor(originX + node.frame.width / 2.0) + contentWidth - backgroundSize.width - 5.0, y: self.centered ? 9.0 : 2.0), size: backgroundSize) } transition.updateFrame(node: container.badgeContainerNode, frame: backgroundFrame) diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 53b10ecb22..e0acc9d09c 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -332,7 +332,7 @@ public class GalleryController: ViewController, StandalonePresentableController private let centralItemRightBarButtonItem = Promise() private let centralItemRightBarButtonItems = Promise<[UIBarButtonItem]?>(nil) private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise<(MessageId, Media)?>(nil) @@ -531,9 +531,9 @@ public class GalleryController: ViewController, StandalonePresentableController } })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, overlayContentNode in self?.galleryNode.updatePresentationState({ - $0.withUpdatedFooterContentNode(footerContentNode) + $0.withUpdatedFooterContentNode(footerContentNode).withUpdatedOverlayContentNode(overlayContentNode) }, transition: .immediate) })) diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 0c82bd5bec..5409b07a5b 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -250,8 +250,8 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture self.updateThumbnailContainerNodeAlpha(transition) } - self.footerNode.updateLayout(layout, footerContentNode: self.presentationState.footerContentNode, thumbnailPanelHeight: thumbnailPanelHeight, transition: transition) - + self.footerNode.updateLayout(layout, footerContentNode: self.presentationState.footerContentNode, overlayContentNode: self.presentationState.overlayContentNode, thumbnailPanelHeight: thumbnailPanelHeight, transition: transition) + let previousContentHeight = self.scrollView.contentSize.height let previousVerticalOffset = self.scrollView.contentOffset.y @@ -276,14 +276,14 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .animated(duration: 0.3, curve: .easeInOut)) - self.footerNode.alpha = alpha + self.footerNode.setVisibilityAlpha(alpha) self.updateThumbnailContainerNodeAlpha(.immediate) }) } else { let alpha: CGFloat = self.areControlsHidden ? 0.0 : 1.0 self.navigationBar?.alpha = alpha self.statusBar?.updateAlpha(alpha, transition: .immediate) - self.footerNode.alpha = alpha + self.footerNode.setVisibilityAlpha(alpha) self.updateThumbnailContainerNodeAlpha(.immediate) } } diff --git a/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift b/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift index 7fd9620cb5..4881b7744e 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerPresentationState.swift @@ -2,16 +2,23 @@ import Foundation public final class GalleryControllerPresentationState { public let footerContentNode: GalleryFooterContentNode? + public let overlayContentNode: GalleryOverlayContentNode? public init() { self.footerContentNode = nil + self.overlayContentNode = nil } - public init(footerContentNode: GalleryFooterContentNode?) { + public init(footerContentNode: GalleryFooterContentNode?, overlayContentNode: GalleryOverlayContentNode?) { self.footerContentNode = footerContentNode + self.overlayContentNode = overlayContentNode } public func withUpdatedFooterContentNode(_ footerContentNode: GalleryFooterContentNode?) -> GalleryControllerPresentationState { - return GalleryControllerPresentationState(footerContentNode: footerContentNode) + return GalleryControllerPresentationState(footerContentNode: footerContentNode, overlayContentNode: self.overlayContentNode) + } + + public func withUpdatedOverlayContentNode(_ overlayContentNode: GalleryOverlayContentNode?) -> GalleryControllerPresentationState { + return GalleryControllerPresentationState(footerContentNode: self.footerContentNode, overlayContentNode: overlayContentNode) } } diff --git a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift index 9fe0dadf41..1d9126eec0 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift @@ -31,3 +31,20 @@ open class GalleryFooterContentNode: ASDisplayNode { completion() } } + +open class GalleryOverlayContentNode: ASDisplayNode { + var visibilityAlpha: CGFloat = 1.0 + open func setVisibilityAlpha(_ alpha: CGFloat) { + self.visibilityAlpha = alpha + } + + open func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + } + + open func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) { + } + + open func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { + completion() + } +} diff --git a/submodules/GalleryUI/Sources/GalleryFooterNode.swift b/submodules/GalleryUI/Sources/GalleryFooterNode.swift index 7537360dce..155f2cc358 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterNode.swift @@ -7,6 +7,7 @@ public final class GalleryFooterNode: ASDisplayNode { private let backgroundNode: ASDisplayNode private var currentFooterContentNode: GalleryFooterContentNode? + private var currentOverlayContentNode: GalleryOverlayContentNode? private var currentLayout: (ContainerViewLayout, CGFloat)? private let controllerInteraction: GalleryControllerInteraction @@ -22,38 +23,59 @@ public final class GalleryFooterNode: ASDisplayNode { self.addSubnode(self.backgroundNode) } - public func updateLayout(_ layout: ContainerViewLayout, footerContentNode: GalleryFooterContentNode?, thumbnailPanelHeight: CGFloat, transition: ContainedViewLayoutTransition) { + private var visibilityAlpha: CGFloat = 1.0 + public func setVisibilityAlpha(_ alpha: CGFloat) { + self.visibilityAlpha = alpha + self.backgroundNode.alpha = alpha + self.currentFooterContentNode?.alpha = alpha + self.currentOverlayContentNode?.setVisibilityAlpha(alpha) + } + + public func updateLayout(_ layout: ContainerViewLayout, footerContentNode: GalleryFooterContentNode?, overlayContentNode: GalleryOverlayContentNode?, thumbnailPanelHeight: CGFloat, transition: ContainedViewLayoutTransition) { self.currentLayout = (layout, thumbnailPanelHeight) let cleanInsets = layout.insets(options: []) - var removeCurrentFooterContentNode: GalleryFooterContentNode? + var dismissedCurrentFooterContentNode: GalleryFooterContentNode? if self.currentFooterContentNode !== footerContentNode { if let currentFooterContentNode = self.currentFooterContentNode { currentFooterContentNode.requestLayout = nil - removeCurrentFooterContentNode = currentFooterContentNode + dismissedCurrentFooterContentNode = currentFooterContentNode } self.currentFooterContentNode = footerContentNode if let footerContentNode = footerContentNode { + footerContentNode.alpha = self.visibilityAlpha footerContentNode.controllerInteraction = self.controllerInteraction footerContentNode.requestLayout = { [weak self] transition in if let strongSelf = self, let (currentLayout, currentThumbnailPanelHeight) = strongSelf.currentLayout { - strongSelf.updateLayout(currentLayout, footerContentNode: strongSelf.currentFooterContentNode, thumbnailPanelHeight: currentThumbnailPanelHeight, transition: transition) + strongSelf.updateLayout(currentLayout, footerContentNode: strongSelf.currentFooterContentNode, overlayContentNode: strongSelf.currentOverlayContentNode, thumbnailPanelHeight: currentThumbnailPanelHeight, transition: transition) } } self.addSubnode(footerContentNode) } } + var dismissedCurrentOverlayContentNode: GalleryOverlayContentNode? + if self.currentOverlayContentNode !== overlayContentNode { + if let currentOverlayContentNode = self.currentOverlayContentNode { + dismissedCurrentOverlayContentNode = currentOverlayContentNode + } + self.currentOverlayContentNode = overlayContentNode + if let overlayContentNode = overlayContentNode { + overlayContentNode.setVisibilityAlpha(self.visibilityAlpha) + self.addSubnode(overlayContentNode) + } + } + var backgroundHeight: CGFloat = 0.0 if let footerContentNode = self.currentFooterContentNode { backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: thumbnailPanelHeight, transition: transition) transition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) - if let removeCurrentFooterContentNode = removeCurrentFooterContentNode { + if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) - footerContentNode.animateIn(fromHeight: removeCurrentFooterContentNode.bounds.height, previousContentNode: removeCurrentFooterContentNode, transition: contentTransition) - removeCurrentFooterContentNode.animateOut(toHeight: backgroundHeight, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak removeCurrentFooterContentNode] in - if let strongSelf = self, let removeCurrentFooterContentNode = removeCurrentFooterContentNode, removeCurrentFooterContentNode !== strongSelf.currentFooterContentNode { - removeCurrentFooterContentNode.removeFromSupernode() + footerContentNode.animateIn(fromHeight: dismissedCurrentFooterContentNode.bounds.height, previousContentNode: dismissedCurrentFooterContentNode, transition: contentTransition) + dismissedCurrentFooterContentNode.animateOut(toHeight: backgroundHeight, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentFooterContentNode] in + if let strongSelf = self, let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode, dismissedCurrentFooterContentNode !== strongSelf.currentFooterContentNode { + dismissedCurrentFooterContentNode.removeFromSupernode() } }) contentTransition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) @@ -61,15 +83,41 @@ public final class GalleryFooterNode: ASDisplayNode { transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) } } else { - if let removeCurrentFooterContentNode = removeCurrentFooterContentNode { - removeCurrentFooterContentNode.removeFromSupernode() + if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { + dismissedCurrentFooterContentNode.removeFromSupernode() } transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight), size: CGSize(width: layout.size.width, height: backgroundHeight))) } + + let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) + if let overlayContentNode = self.currentOverlayContentNode { + overlayContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: backgroundHeight, transition: transition) + transition.updateFrame(node: overlayContentNode, frame: CGRect(origin: CGPoint(), size: layout.size)) + + overlayContentNode.animateIn(previousContentNode: dismissedCurrentOverlayContentNode, transition: contentTransition) + if let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode { + dismissedCurrentOverlayContentNode.animateOut(nextContentNode: overlayContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentOverlayContentNode] in + if let strongSelf = self, let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode, dismissedCurrentOverlayContentNode !== strongSelf.currentOverlayContentNode { + dismissedCurrentOverlayContentNode.removeFromSupernode() + } + }) + } + } else { + if let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode { + dismissedCurrentOverlayContentNode.animateOut(nextContentNode: overlayContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentOverlayContentNode] in + if let strongSelf = self, let dismissedCurrentOverlayContentNode = dismissedCurrentOverlayContentNode, dismissedCurrentOverlayContentNode !== strongSelf.currentOverlayContentNode { + dismissedCurrentOverlayContentNode.removeFromSupernode() + } + }) + } + } } override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if let overlayResult = self.currentOverlayContentNode?.hitTest(point, with: event) { + return overlayResult + } if !self.backgroundNode.frame.contains(point) { return nil } diff --git a/submodules/GalleryUI/Sources/GalleryItemNode.swift b/submodules/GalleryUI/Sources/GalleryItemNode.swift index ce3d8b3c59..615bdde364 100644 --- a/submodules/GalleryUI/Sources/GalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/GalleryItemNode.swift @@ -21,6 +21,8 @@ open class GalleryItemNode: ASDisplayNode { } public var toggleControlsVisibility: () -> Void = { } + public var goToPreviousItem: () -> Void = { } + public var goToNextItem: () -> Void = { } public var dismiss: () -> Void = { } public var beginCustomDismiss: () -> Void = { } public var completeCustomDismiss: () -> Void = { } @@ -54,8 +56,8 @@ open class GalleryItemNode: ASDisplayNode { return .single(nil) } - open func footerContent() -> Signal { - return .single(nil) + open func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((nil, nil)) } open func navigationStyle() -> Signal { diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index fea7e407af..125b432cdc 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -241,6 +241,20 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate { private func makeNodeForItem(at index: Int) -> GalleryItemNode { let node = self.items[index].node() node.toggleControlsVisibility = self.toggleControlsVisibility + node.goToPreviousItem = { [weak self] in + if let strongSelf = self { + if let index = strongSelf.centralItemIndex, index > 0 { + strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index - 1)) + } + } + } + node.goToNextItem = { [weak self] in + if let strongSelf = self { + if let index = strongSelf.centralItemIndex, index < strongSelf.items.count - 1 { + strongSelf.transaction(GalleryPagerTransaction(deleteItems: [], insertItems: [], updateItems: [], focusOnItem: index + 1)) + } + } + } node.dismiss = self.dismiss node.beginCustomDismiss = self.beginCustomDismiss node.completeCustomDismiss = self.completeCustomDismiss @@ -314,7 +328,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate { } } - if centralItemIndex != items.count - 1 { + if centralItemIndex != self.items.count - 1 { if self.shouldLoadItems(force: forceLoad) && self.visibleItemNode(at: centralItemIndex + 1) == nil { let node = self.makeNodeForItem(at: centralItemIndex + 1) node.frame = centralItemNode.frame.offsetBy(dx: centralItemNode.frame.size.width + self.pageGap, dy: 0.0) diff --git a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift index f4f24f1221..834d6758d1 100644 --- a/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatAnimationGalleryItem.swift @@ -325,8 +325,8 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode { return self._rightBarButtonItems.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift index 1537d93a17..2be4d488cc 100644 --- a/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatDocumentGalleryItem.swift @@ -375,8 +375,8 @@ class ChatDocumentGalleryItemNode: ZoomableContentGalleryItemNode, WKNavigationD self.statusNodeContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue, removeOnCompletion: false) } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift index c0714f5fd1..753b5cc904 100644 --- a/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatExternalFileGalleryItem.swift @@ -310,8 +310,8 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode { self.statusNodeContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue, removeOnCompletion: false) } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 083195070c..e07033342e 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -505,8 +505,8 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { return self._rightBarButtonItem.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } @objc func statusPressed() { diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 183bce8efd..dc01efd988 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -145,6 +145,87 @@ private final class UniversalVideoGalleryItemPictureInPictureNode: ASDisplayNode } } +private let soundOnImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/SoundOn"), color: .white) +private let soundOffImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/SoundOff"), color: .white) +private var roundButtonBackgroundImage = { + return generateImage(CGSize(width: 42.0, height: 42), rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + context.setFillColor(UIColor(white: 0.0, alpha: 0.5).cgColor) + context.fillEllipse(in: bounds) + }) +}() + +private final class UniversalVideoGalleryItemOverlayNode: GalleryOverlayContentNode { + private let soundButtonNode: HighlightableButtonNode + private var validLayout: (CGSize, LayoutMetrics, CGFloat, CGFloat, CGFloat)? + + override init() { + self.soundButtonNode = HighlightableButtonNode() + self.soundButtonNode.alpha = 0.0 + self.soundButtonNode.setBackgroundImage(roundButtonBackgroundImage, for: .normal) + self.soundButtonNode.setImage(soundOffImage, for: .normal) + self.soundButtonNode.setImage(soundOnImage, for: .selected) + self.soundButtonNode.setImage(soundOnImage, for: [.selected, .highlighted]) + + super.init() + + self.soundButtonNode.addTarget(self, action: #selector(self.soundButtonPressed), forControlEvents: .touchUpInside) + self.addSubnode(self.soundButtonNode) + } + + func hide() { + self.soundButtonNode.isHidden = true + } + + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, metrics, leftInset, rightInset, bottomInset) + + let soundButtonDiameter: CGFloat = 42.0 + let inset: CGFloat = 12.0 + let effectiveBottomInset = self.visibilityAlpha < 1.0 ? 0.0 : bottomInset + let soundButtonFrame = CGRect(origin: CGPoint(x: size.width - soundButtonDiameter - inset - rightInset, y: size.height - soundButtonDiameter - inset - effectiveBottomInset), size: CGSize(width: soundButtonDiameter, height: soundButtonDiameter)) + transition.updateFrame(node: self.soundButtonNode, frame: soundButtonFrame) + } + + override func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) { + transition.updateAlpha(node: self.soundButtonNode, alpha: 1.0) + } + + override func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { + transition.updateAlpha(node: self.soundButtonNode, alpha: 0.0) + } + + override func setVisibilityAlpha(_ alpha: CGFloat) { + super.setVisibilityAlpha(alpha) + self.updateSoundButtonVisibility() + } + + func updateSoundButtonVisibility() { + if self.soundButtonNode.isSelected { + self.soundButtonNode.alpha = self.visibilityAlpha + } else { + self.soundButtonNode.alpha = 1.0 + } + + if let validLayout = self.validLayout { + self.updateLayout(size: validLayout.0, metrics: validLayout.1, leftInset: validLayout.2, rightInset: validLayout.3, bottomInset: validLayout.4, transition: .animated(duration: 0.3, curve: .easeInOut)) + } + } + + @objc func soundButtonPressed() { + self.soundButtonNode.isSelected = !self.soundButtonNode.isSelected + self.updateSoundButtonVisibility() + } + + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.soundButtonNode.frame.contains(point) { + return nil + } + return super.hitTest(point, with: event) + } +} + private struct FetchControls { let fetch: () -> Void let cancel: () -> Void @@ -161,6 +242,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private let scrubberView: ChatVideoGalleryItemScrubberView private let footerContentNode: ChatItemGalleryFooterContentNode + private let overlayContentNode: UniversalVideoGalleryItemOverlayNode private var videoNode: UniversalVideoNode? private var videoFramePreview: MediaPlayerFramePreview? @@ -206,6 +288,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.footerContentNode.performAction = performAction self.footerContentNode.openActionOptions = openActionOptions + self.overlayContentNode = UniversalVideoGalleryItemOverlayNode() + self.statusButtonNode = HighlightableButtonNode() self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) self.statusNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 50.0, height: 50.0)) @@ -398,6 +482,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { videoNode.backgroundColor = videoNode.ownsContentNode ? UIColor.black : UIColor(rgb: 0x333335) if item.fromPlayingVideo { videoNode.canAttachContent = false + self.overlayContentNode.hide() } else { self.updateDisplayPlaceholder(!videoNode.ownsContentNode) } @@ -982,7 +1067,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { transformedSuperFrame = transformedSuperFrame.offsetBy(dx: videoNode.position.x - previousFrame.center.x, dy: videoNode.position.y - previousFrame.center.y) } - let initialScale: CGFloat = 1.0 //min(videoNode.layer.bounds.width / node.0.view.bounds.width, videoNode.layer.bounds.height / node.0.view.bounds.height) + let initialScale: CGFloat = 1.0 let targetScale = max(transformedFrame.size.width / videoNode.layer.bounds.size.width, transformedFrame.size.height / videoNode.layer.bounds.size.height) videoNode.backgroundColor = .clear @@ -1197,7 +1282,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, self.overlayContentNode)) } } diff --git a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift index 7c7851232a..a0abf7e711 100644 --- a/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/ZoomableContentGalleryItemNode.swift @@ -3,8 +3,36 @@ import UIKit import Display import AsyncDisplayKit +private let leftFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + + let gradientColors = [UIColor.black.withAlphaComponent(0.5).cgColor, UIColor.black.withAlphaComponent(0.0).cgColor] as CFArray + + var locations: [CGFloat] = [0.0, 1.0] + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions()) +}) + +private let rightFadeImage = generateImage(CGSize(width: 64.0, height: 1.0), opaque: false, rotatedContext: { size, context in + let bounds = CGRect(origin: CGPoint(), size: size) + context.clear(bounds) + + let gradientColors = [UIColor.black.withAlphaComponent(0.0).cgColor, UIColor.black.withAlphaComponent(0.5).cgColor] as CFArray + + var locations: [CGFloat] = [0.0, 1.0] + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: gradientColors, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 64.0, y: 0.0), options: CGGradientDrawingOptions()) +}) + open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate { public let scrollNode: ASScrollNode + private let leftFadeNode: ASImageNode + private let rightFadeNode: ASImageNode private var containerLayout: ContainerViewLayout? @@ -32,6 +60,16 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate self.scrollNode.view.contentInsetAdjustmentBehavior = .never } + self.leftFadeNode = ASImageNode() + self.leftFadeNode.contentMode = .scaleToFill + self.leftFadeNode.image = leftFadeImage + self.leftFadeNode.isHidden = true + + self.rightFadeNode = ASImageNode() + self.rightFadeNode.contentMode = .scaleToFill + self.rightFadeNode.image = rightFadeImage + self.rightFadeNode.isHidden = true + super.init() self.scrollNode.view.delegate = self @@ -42,41 +80,69 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate self.scrollNode.view.delaysContentTouches = false let tapRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.contentTap(_:))) - tapRecognizer.tapActionAtPoint = { _ in + tapRecognizer.tapActionAtPoint = { [weak self] location in + if let strongSelf = self { + if location.x < 44.0 || location.x > strongSelf.frame.width - 44.0 { + return .waitForSingleTap + } + } return .waitForDoubleTap } + tapRecognizer.highlight = { [weak self] location in + if let strongSelf = self { + if let location = location, location.x < 44.0 { + strongSelf.leftFadeNode.isHidden = false + } else { + strongSelf.leftFadeNode.isHidden = true + } + if let location = location, location.x > strongSelf.frame.width - 44.0 { + strongSelf.rightFadeNode.isHidden = false + } else { + strongSelf.rightFadeNode.isHidden = true + } + } + } self.scrollNode.view.addGestureRecognizer(tapRecognizer) + self.addSubnode(self.scrollNode) + self.addSubnode(self.leftFadeNode) + self.addSubnode(self.rightFadeNode) } @objc open func contentTap(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { if recognizer.state == .ended { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - switch gesture { - case .tap: - self.toggleControlsVisibility() - case .doubleTap: - if let contentView = self.zoomableContent?.1.view, self.scrollNode.view.zoomScale.isLessThanOrEqualTo(self.scrollNode.view.minimumZoomScale) { - let pointInView = self.scrollNode.view.convert(location, to: contentView) - - let newZoomScale = self.scrollNode.view.maximumZoomScale - let scrollViewSize = self.scrollNode.view.bounds.size - - let w = scrollViewSize.width / newZoomScale - let h = scrollViewSize.height / newZoomScale - let x = pointInView.x - (w / 2.0) - let y = pointInView.y - (h / 2.0) - - let rectToZoomTo = CGRect(x: x, y: y, width: w, height: h) - - self.scrollNode.view.zoom(to: rectToZoomTo, animated: true) - } else { - self.scrollNode.view.setZoomScale(self.scrollNode.view.minimumZoomScale, animated: true) - } - default: - break + if location.x < 44.0 { + self.goToPreviousItem() + } else if location.x > self.frame.width - 44.0 { + self.goToNextItem() + } else { + switch gesture { + case .tap: + self.toggleControlsVisibility() + case .doubleTap: + if let contentView = self.zoomableContent?.1.view, self.scrollNode.view.zoomScale.isLessThanOrEqualTo(self.scrollNode.view.minimumZoomScale) { + let pointInView = self.scrollNode.view.convert(location, to: contentView) + + let newZoomScale = self.scrollNode.view.maximumZoomScale + let scrollViewSize = self.scrollNode.view.bounds.size + + let w = scrollViewSize.width / newZoomScale + let h = scrollViewSize.height / newZoomScale + let x = pointInView.x - (w / 2.0) + let y = pointInView.y - (h / 2.0) + + let rectToZoomTo = CGRect(x: x, y: y, width: w, height: h) + + self.scrollNode.view.zoom(to: rectToZoomTo, animated: true) + } else { + self.scrollNode.view.setZoomScale(self.scrollNode.view.minimumZoomScale, animated: true) + } + default: + break + } } } } @@ -93,6 +159,9 @@ open class ZoomableContentGalleryItemNode: GalleryItemNode, UIScrollViewDelegate } self.containerLayout = layout + self.leftFadeNode.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) + self.rightFadeNode.frame = CGRect(x: layout.size.width - layout.size.width * 0.2, y: 0.0, width: layout.size.width * 0.2, height: layout.size.height) + if shouldResetContents { var previousFrame: CGRect? var previousScale: CGFloat? diff --git a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift index 9254384396..1d0c082ae5 100644 --- a/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift +++ b/submodules/InstantPageUI/Sources/InstantImageGalleryItem.swift @@ -301,7 +301,7 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index 0e32aadb82..d50fc2b478 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -170,7 +170,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable private let centralItemTitleView = Promise() private let centralItemRightBarButtonItem = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -243,7 +243,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable self?.navigationItem.rightBarButtonItem = rightBarButtonItem })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift index 2b0988c6d8..b9da7f99eb 100644 --- a/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift +++ b/submodules/ItemListPeerActionItem/Sources/ItemListPeerActionItem.swift @@ -12,6 +12,11 @@ public enum ItemListPeerActionItemHeight { case peerList } +public enum ItemListPeerActionItemColor { + case accent + case destructive +} + public class ItemListPeerActionItem: ListViewItem, ItemListItem { let presentationData: ItemListPresentationData let icon: UIImage? @@ -19,16 +24,18 @@ public class ItemListPeerActionItem: ListViewItem, ItemListItem { public let alwaysPlain: Bool let editing: Bool let height: ItemListPeerActionItemHeight + let color: ItemListPeerActionItemColor public let sectionId: ItemListSectionId let action: (() -> Void)? - public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, editing: Bool, action: (() -> Void)?) { + public init(presentationData: ItemListPresentationData, icon: UIImage?, title: String, alwaysPlain: Bool = false, sectionId: ItemListSectionId, height: ItemListPeerActionItemHeight = .peerList, color: ItemListPeerActionItemColor = .accent, editing: Bool, action: (() -> Void)?) { self.presentationData = presentationData self.icon = icon self.title = title self.alwaysPlain = alwaysPlain self.editing = editing self.height = height + self.color = color self.sectionId = sectionId self.action = action } @@ -167,7 +174,15 @@ class ItemListPeerActionItemNode: ListViewItemNode { let editingOffset: CGFloat = (item.editing ? 38.0 : 0.0) - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemAccentColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let textColor: UIColor + switch item.color { + case .accent: + textColor = item.presentationData.theme.list.itemAccentColor + case .destructive: + textColor = item.presentationData.theme.list.itemDestructiveColor + } + + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - editingOffset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let separatorHeight = UIScreenPixel diff --git a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift index 0eb1793f6c..f707e88839 100644 --- a/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift +++ b/submodules/ItemListStickerPackItem/Sources/ItemListStickerPackItem.swift @@ -31,6 +31,7 @@ public enum ItemListStickerPackItemControl: Equatable { case none case installation(installed: Bool) case selection + case check(checked: Bool) } public final class ItemListStickerPackItem: ListViewItem, ItemListItem { @@ -305,6 +306,8 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { case .selection: rightInset += 16.0 checkImage = PresentationResourcesItemList.checkIconImage(item.presentationData.theme) + case .check: + rightInset += 16.0 } var unreadImage: UIImage? @@ -531,6 +534,10 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode { strongSelf.selectionIconNode.image = image strongSelf.selectionIconNode.frame = CGRect(origin: CGPoint(x: params.width - params.rightInset - image.size.width - floor((44.0 - image.size.width) / 2.0), y: floor((contentSize.height - image.size.height) / 2.0)), size: image.size) } + case let .check(checked): + strongSelf.installationActionNode.isHidden = true + strongSelf.installationActionImageNode.isHidden = true + strongSelf.selectionIconNode.isHidden = true } if strongSelf.backgroundNode.supernode == nil { diff --git a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift index d8a06b4494..b2604b8881 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift @@ -68,7 +68,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo private let centralItemTitle = Promise() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -123,7 +123,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift b/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift index b4f80aa4d5..857c233cc3 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentImageGalleryItem.swift @@ -210,8 +210,8 @@ final class SecureIdDocumentGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 30c25a1b5b..cb2f0a9d82 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -118,7 +118,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr private let centralItemTitle = Promise() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let _hiddenMedia = Promise(nil) @@ -232,7 +232,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift index 4789f0c18f..d2db820983 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/PeerAvatarImageGalleryItem.swift @@ -355,7 +355,7 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/PeerInfoUI/BUCK b/submodules/PeerInfoUI/BUCK index 47da260275..16d723277d 100644 --- a/submodules/PeerInfoUI/BUCK +++ b/submodules/PeerInfoUI/BUCK @@ -64,6 +64,7 @@ static_library( "//submodules/TelegramIntents:TelegramIntents", "//submodules/SolidRoundedButtonNode:SolidRoundedButtonNode", "//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader", + "//submodules/StatisticsUI:StatisticsUI", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/PeersNearbyUI/BUCK b/submodules/PeersNearbyUI/BUCK index 5a6ca7965b..a6c565b2b6 100644 --- a/submodules/PeersNearbyUI/BUCK +++ b/submodules/PeersNearbyUI/BUCK @@ -26,6 +26,8 @@ static_library( "//submodules/PeersNearbyIconNode:PeersNearbyIconNode", "//submodules/Geocoding:Geocoding", "//submodules/AppBundle:AppBundle", + "//submodules/AnimatedStickerNode:AnimatedStickerNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", ], frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift index 5c6a28bdae..32b5157750 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyController.swift @@ -20,6 +20,9 @@ import TelegramPermissionsUI import ItemListPeerActionItem import Geocoding import AppBundle +import ContextUI +import TelegramNotices +import TelegramStringFormatting private struct PeerNearbyEntry { let peer: (Peer, CachedPeerData?) @@ -49,13 +52,19 @@ private func arePeerNearbyArraysEqual(_ lhs: [PeerNearbyEntry], _ rhs: [PeerNear private final class PeersNearbyControllerArguments { let context: AccountContext + let toggleVisibility: (Bool) -> Void + let openProfile: (Peer) -> Void let openChat: (Peer) -> Void let openCreateGroup: (Double, Double, String?) -> Void + let contextAction: (Peer, ASDisplayNode, ContextGesture?) -> Void - init(context: AccountContext, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void) { + init(context: AccountContext, toggleVisibility: @escaping (Bool) -> Void, openProfile: @escaping (Peer) -> Void, openChat: @escaping (Peer) -> Void, openCreateGroup: @escaping (Double, Double, String?) -> Void, contextAction: @escaping (Peer, ASDisplayNode, ContextGesture?) -> Void) { self.context = context + self.toggleVisibility = toggleVisibility + self.openProfile = openProfile self.openChat = openChat self.openCreateGroup = openCreateGroup + self.contextAction = contextAction } } @@ -71,6 +80,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { case usersHeader(PresentationTheme, String, Bool) case empty(PresentationTheme, String) + case visibility(PresentationTheme, String, Bool) case user(Int32, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PeerNearbyEntry) case groupsHeader(PresentationTheme, String, Bool) @@ -84,7 +94,7 @@ private enum PeersNearbyEntry: ItemListNodeEntry { switch self { case .header: return PeersNearbySection.header.rawValue - case .usersHeader, .empty, .user: + case .usersHeader, .empty, .visibility, .user: return PeersNearbySection.users.rawValue case .groupsHeader, .createGroup, .group: return PeersNearbySection.groups.rawValue @@ -101,8 +111,10 @@ private enum PeersNearbyEntry: ItemListNodeEntry { return 1 case .empty: return 2 + case .visibility: + return 3 case let .user(index, _, _, _, _, _): - return 3 + index + return 4 + index case .groupsHeader: return 1000 case .createGroup: @@ -136,6 +148,13 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } else { return false } + case let .visibility(lhsTheme, lhsText, lhsStop): + if case let .visibility(rhsTheme, rhsText, rhsStop) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsStop == rhsStop { + return true + } else { + return false + } + case let .user(lhsIndex, lhsTheme, lhsStrings, lhsDateTimeFormat, lhsDisplayOrder, lhsPeer): if case let .user(rhsIndex, rhsTheme, rhsStrings, rhsDateTimeFormat, rhsDisplayOrder, rhsPeer) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsDisplayOrder == rhsDisplayOrder, arePeersNearbyEqual(lhsPeer, rhsPeer) { return true @@ -199,10 +218,20 @@ private enum PeersNearbyEntry: ItemListNodeEntry { return ItemListSectionHeaderItem(presentationData: presentationData, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .empty(theme, text): return ItemListPlaceholderItem(theme: theme, text: text, sectionId: self.section, style: .blocks) + case let .visibility(theme, title, stop): + return ItemListPeerActionItem(presentationData: presentationData, icon: stop ? PresentationResourcesItemList.makeInvisibleIcon(theme) : PresentationResourcesItemList.makeVisibleIcon(theme), title: title, alwaysPlain: false, sectionId: self.section, color: stop ? .destructive : .accent, editing: false, action: { + arguments.toggleVisibility(!stop) + }) case let .user(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): + var text = strings.Map_DistanceAway(stringForDistance(peer.distance)).0 + if peer.peer.0.id == arguments.context.account.peerId { + text = strings.PeopleNearby_VisibleUntil(humanReadableStringForTimestamp(strings: strings, dateTimeFormat: dateTimeFormat, timestamp: peer.expires)).0 + } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: .text(strings.Map_DistanceAway(stringForDistance(peer.distance)).0), label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { - arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + arguments.openProfile(peer.peer.0) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) case let .groupsHeader(theme, text, loading): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, activityIndicator: loading ? .left : .none, sectionId: self.section) case let .createGroup(theme, title, latitude, longitude, address): @@ -220,7 +249,9 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) case let .channelsHeader(theme, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .channel(_, theme, strings, dateTimeFormat, nameDisplayOrder, peer): @@ -232,7 +263,9 @@ private enum PeersNearbyEntry: ItemListNodeEntry { } return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer.peer.0, aliasHandling: .standard, nameColor: .primary, nameStyle: .distinctBold, presence: nil, text: text, label: .none, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), revealOptions: nil, switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { arguments.openChat(peer.peer.0) - }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, hasTopGroupInset: false, tag: nil) + }, setPeerIdWithRevealedOptions: { _, _ in }, removePeer: { _ in }, toggleUpdated: nil, contextAction: { node, gesture in + arguments.contextAction(peer.peer.0, node, gesture) + }, hasTopGroupInset: false, tag: nil) } } } @@ -241,37 +274,41 @@ private struct PeersNearbyData: Equatable { let latitude: Double let longitude: Double let address: String? + let visible: Bool let users: [PeerNearbyEntry] let groups: [PeerNearbyEntry] let channels: [PeerNearbyEntry] - init(latitude: Double, longitude: Double, address: String?, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { + init(latitude: Double, longitude: Double, address: String?, visible: Bool, users: [PeerNearbyEntry], groups: [PeerNearbyEntry], channels: [PeerNearbyEntry]) { self.latitude = latitude self.longitude = longitude self.address = address + self.visible = visible self.users = users self.groups = groups self.channels = channels } static func ==(lhs: PeersNearbyData, rhs: PeersNearbyData) -> Bool { - return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) + return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude && lhs.address == rhs.address && lhs.visible == rhs.visible && arePeerNearbyArraysEqual(lhs.users, rhs.users) && arePeerNearbyArraysEqual(lhs.groups, rhs.groups) && arePeerNearbyArraysEqual(lhs.channels, rhs.channels) } } private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationData: PresentationData, displayLoading: Bool) -> [PeersNearbyEntry] { var entries: [PeersNearbyEntry] = [] - entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_Description)) + entries.append(.header(presentationData.theme, presentationData.strings.PeopleNearby_DiscoverDescription)) entries.append(.usersHeader(presentationData.theme, presentationData.strings.PeopleNearby_Users.uppercased(), displayLoading && data == nil)) + + let visible = data?.visible ?? false + entries.append(.visibility(presentationData.theme, visible ? presentationData.strings.PeopleNearby_MakeInvisible : presentationData.strings.PeopleNearby_MakeVisible, visible)) + if let data = data, !data.users.isEmpty { var i: Int32 = 0 for user in data.users { entries.append(.user(i, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, user)) i += 1 } - } else { - entries.append(.empty(presentationData.theme, presentationData.strings.PeopleNearby_UsersEmpty)) } entries.append(.groupsHeader(presentationData.theme, presentationData.strings.PeopleNearby_Groups.uppercased(), displayLoading && data == nil)) @@ -295,11 +332,94 @@ private func peersNearbyControllerEntries(data: PeersNearbyData?, presentationDa return entries } +private final class ContextControllerContentSourceImpl: ContextControllerContentSource { + let controller: ViewController + weak var sourceNode: ASDisplayNode? + + let navigationController: NavigationController? = nil + + let passthroughTouches: Bool = true + + init(controller: ViewController, sourceNode: ASDisplayNode?) { + self.controller = controller + self.sourceNode = sourceNode + } + + func transitionInfo() -> ContextControllerTakeControllerInfo? { + let sourceNode = self.sourceNode + return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in + if let sourceNode = sourceNode { + return (sourceNode, sourceNode.bounds) + } else { + return nil + } + }) + } + + func animatedIn() { + } +} + +private func peerNearbyContextMenuItems(context: AccountContext, peerId: PeerId, present: @escaping (ViewController) -> Void) -> Signal<[ContextMenuItem], NoError> { + let presentationData = context.sharedContext.currentPresentationData.with({ $0 }) + return context.account.postbox.transaction { transaction -> [ContextMenuItem] in + var items: [ContextMenuItem] = [] +// +// let peer = transaction.getPeer(peerId) +// +// if let peer = peer as? TelegramUser { +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// f(.default) +// }))) +// } else { +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeopleNearby_Context_JoinGroup, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// let _ = (joinChannel(account: context.account, peerId: peerId) |> deliverOnMainQueue).start(next: { participant in +// f(.default) +// }, error: { error in +//// if let strongSelf = self { +//// if case .tooMuchJoined = error { +//// if let parentNavigationController = strongSelf.parentNavigationController { +//// let context = strongSelf.context +//// let link = strongSelf.link +//// let navigateToPeer = strongSelf.navigateToPeer +//// let resolvedState = strongSelf.resolvedState +//// parentNavigationController.pushViewController(oldChannelsController(context: strongSelf.context, intent: .join, completed: { [weak parentNavigationController] value in +//// if value { +//// (parentNavigationController?.viewControllers.last as? ViewController)?.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: navigateToPeer, parentNavigationController: parentNavigationController, resolvedState: resolvedState), in: .window(.root)) +//// } +//// })) +//// } else { +//// strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Join_ChannelsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) +//// } +//// strongSelf.dismiss() +//// } +//// } +// }) +// }))) +// +// items.append(.action(ContextMenuActionItem(text: presentationData.strings.PeopleNearby_Context_UnrelatedLocation, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Report"), color: theme.contextMenu.primaryColor) }, action: { _, f in +// let _ = (TelegramCore.reportPeer(account: context.account, peerId: peerId, reason: .irrelevantLocation) +// |> deliverOnMainQueue).start(completed: { +// let _ = ApplicationSpecificNotice.setIrrelevantPeerGeoReport(postbox: context.account.postbox, peerId: peerId).start() +// +// present(textAlertController(context: context, title: nil, text: presentationData.strings.ReportPeer_AlertSuccess, actions: [TextAlertAction(type: TextAlertActionType.defaultAction, title: presentationData.strings.Common_OK, action: {})])) +// }) +// f(.default) +// }))) +// } + + return items + } +} + + public func peersNearbyController(context: AccountContext) -> ViewController { var pushControllerImpl: ((ViewController) -> Void)? var replaceAllButRootControllerImpl: ((ViewController, Bool) -> Void)? var replaceTopControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var presentInGlobalOverlayImpl: ((ViewController) -> Void)? + var navigateToProfileImpl: ((Peer) -> Void)? var navigateToChatImpl: ((Peer) -> Void)? let actionsDisposable = DisposableSet() @@ -309,7 +429,27 @@ public func peersNearbyController(context: AccountContext) -> ViewController { let dataPromise = Promise(nil) let addressPromise = Promise(nil) - let arguments = PeersNearbyControllerArguments(context: context, openChat: { peer in + let coordinatePromise = Promise(nil) + coordinatePromise.set(.single(nil) |> then(currentLocationManagerCoordinate(manager: context.sharedContext.locationManager!, timeout: 5.0))) + + let arguments = PeersNearbyControllerArguments(context: context, toggleVisibility: { visible in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + + if visible { + presentControllerImpl?(textAlertController(context: context, title: presentationData.strings.PeopleNearby_MakeVisibleTitle, text: presentationData.strings.PeopleNearby_MakeVisibleDescription, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { + let _ = (coordinatePromise.get() + |> deliverOnMainQueue).start(next: { coordinate in + if let coordinate = coordinate { + let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .visible(latitude: coordinate.latitude, longitude: coordinate.longitude), background: false).start() + } + }) + })]), nil) + } else { + let _ = peersNearbyUpdateVisibility(network: context.account.network, stateManager: context.account.stateManager, update: .invisible, background: false).start() + } + }, openProfile: { peer in + navigateToProfileImpl?(peer) + }, openChat: { peer in navigateToChatImpl?(peer) }, openCreateGroup: { latitude, longitude, address in let presentationData = context.sharedContext.currentPresentationData.with { $0 } @@ -350,16 +490,24 @@ public func peersNearbyController(context: AccountContext) -> ViewController { presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) } })) + }, contextAction: { peer, node, gesture in + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true)) + chatController.canReadHistory.set(false) + let contextController = ContextController(account: context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: peerNearbyContextMenuItems(context: context, peerId: peer.id, present: { c in + presentControllerImpl?(c, nil) + }), reactionItems: [], gesture: gesture) + presentInGlobalOverlayImpl?(contextController) }) - let dataSignal: Signal = currentLocationManagerCoordinate(manager: context.sharedContext.locationManager!, timeout: 5.0) + let dataSignal: Signal = coordinatePromise.get() |> mapToSignal { coordinate -> Signal in guard let coordinate = coordinate else { return .single(nil) } return Signal { subscriber in - let peersNearbyContext = PeersNearbyContext(network: context.account.network, accountStateManager: context.account.stateManager, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude)) + let peersNearbyContext = PeersNearbyContext(network: context.account.network, stateManager: context.account.stateManager, coordinate: (latitude: coordinate.latitude, longitude: coordinate.longitude)) let peersNearby: Signal = combineLatest(peersNearbyContext.get(), addressPromise.get()) |> mapToSignal { peersNearby, address -> Signal<([PeerNearby]?, String?), NoError> in @@ -379,17 +527,26 @@ public func peersNearbyController(context: AccountContext) -> ViewController { return context.account.postbox.transaction { transaction -> PeersNearbyData? in var users: [PeerNearbyEntry] = [] var groups: [PeerNearbyEntry] = [] + var visible = false for peerNearby in peersNearby { - if peerNearby.id != context.account.peerId, let peer = transaction.getPeer(peerNearby.id) { - if peerNearby.id.namespace == Namespaces.Peer.CloudUser { - users.append(PeerNearbyEntry(peer: (peer, nil), expires: peerNearby.expires, distance: peerNearby.distance)) - } else { - let cachedData = transaction.getPeerCachedData(peerId: peerNearby.id) as? CachedChannelData - groups.append(PeerNearbyEntry(peer: (peer, cachedData), expires: peerNearby.expires, distance: peerNearby.distance)) - } + switch peerNearby { + case let .peer(id, expires, distance): + if let peer = transaction.getPeer(id) { + if id.namespace == Namespaces.Peer.CloudUser { + users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: distance)) + } else { + let cachedData = transaction.getPeerCachedData(peerId: id) as? CachedChannelData + groups.append(PeerNearbyEntry(peer: (peer, cachedData), expires: expires, distance: distance)) + } + } + case let .selfPeer(expires): + visible = true + if let peer = transaction.getPeer(context.account.peerId) { + users.append(PeerNearbyEntry(peer: (peer, nil), expires: expires, distance: 0)) + } } } - return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, users: users, groups: groups, channels: []) + return PeersNearbyData(latitude: coordinate.latitude, longitude: coordinate.longitude, address: address, visible: visible, users: users, groups: groups, channels: []) } } @@ -438,6 +595,11 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller.didDisappear = { [weak controller] _ in controller?.clearItemNodesHighlight(animated: true) } + navigateToProfileImpl = { [weak controller] peer in + if let navigationController = controller?.navigationController as? NavigationController, let controller = context.sharedContext.makePeerInfoController(context: context, peer: peer, mode: .generic) { + (navigationController as? NavigationController)?.pushViewController(controller) + } + } navigateToChatImpl = { [weak controller] peer in if let navigationController = controller?.navigationController as? NavigationController { context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer.id), keepStack: .always, purposefulAction: { [weak navigationController] in @@ -467,6 +629,10 @@ public func peersNearbyController(context: AccountContext) -> ViewController { controller.present(c, in: .window(.root), with: p) } } - + presentInGlobalOverlayImpl = { [weak controller] c in + if let controller = controller { + controller.presentInGlobalOverlay(c) + } + } return controller } diff --git a/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift b/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift index 7bbb9e9428..ed5a84dc13 100644 --- a/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift +++ b/submodules/PeersNearbyUI/Sources/PeersNearbyHeaderItem.swift @@ -6,7 +6,8 @@ import SwiftSignalKit import TelegramPresentationData import ItemListUI import PresentationDataUtils -import PeersNearbyIconNode +import AnimatedStickerNode +import AppBundle class PeersNearbyHeaderItem: ListViewItem, ItemListItem { let theme: PresentationTheme @@ -60,7 +61,7 @@ private let titleFont = Font.regular(13.0) class PeersNearbyHeaderItemNode: ListViewItemNode { private let titleNode: TextNode - private var iconNode: PeersNearbyIconNode? + private var animationNode: AnimatedStickerNode private var item: PeersNearbyHeaderItem? @@ -70,24 +71,29 @@ class PeersNearbyHeaderItemNode: ListViewItemNode { self.titleNode.contentMode = .left self.titleNode.contentsScale = UIScreen.main.scale + self.animationNode = AnimatedStickerNode() + if let path = getAppBundle().path(forResource: "Compass", ofType: "tgs") { + self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(path: path), width: 192, height: 192, playbackMode: .once, mode: .direct) + self.animationNode.visibility = true + } + super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.titleNode) + self.addSubnode(self.animationNode) } func asyncLayout() -> (_ item: PeersNearbyHeaderItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { let makeTitleLayout = TextNode.asyncLayout(self.titleNode) return { item, params, neighbors in - let leftInset: CGFloat = 48.0 + params.leftInset + let leftInset: CGFloat = 32.0 + params.leftInset let topInset: CGFloat = 92.0 let attributedText = NSAttributedString(string: item.text, font: titleFont, textColor: item.theme.list.freeTextColor) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let contentSize: CGSize - - contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height) + let contentSize = CGSize(width: params.width, height: topInset + titleLayout.size.height) let insets = itemListNeighborsGroupedInsets(neighbors) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) @@ -96,22 +102,13 @@ class PeersNearbyHeaderItemNode: ListViewItemNode { if let strongSelf = self { strongSelf.item = item strongSelf.accessibilityLabel = attributedText.string - - let iconNode: PeersNearbyIconNode - if let node = strongSelf.iconNode { - iconNode = node - iconNode.updateTheme(item.theme) - } else { - iconNode = PeersNearbyIconNode(theme: item.theme) - strongSelf.iconNode = iconNode - strongSelf.addSubnode(iconNode) - } - - let iconSize = CGSize(width: 60.0, height: 60.0) - iconNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: 5.0), size: iconSize) + + let iconSize = CGSize(width: 96.0, height: 96.0) + strongSelf.animationNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: -10.0), size: iconSize) + strongSelf.animationNode.updateLayout(size: iconSize) let _ = titleApply() - strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset), size: titleLayout.size) + strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleLayout.size.width) / 2.0), y: topInset + 8.0), size: titleLayout.size) } }) } diff --git a/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift b/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift new file mode 100644 index 0000000000..0fa053ebd0 --- /dev/null +++ b/submodules/PresentationDataUtils/Sources/SpecialTabBarIcons.swift @@ -0,0 +1,5 @@ +import Foundation + +public func useSpecialTabBarIcons() -> Bool { + return (Date(timeIntervalSince1970: 1581638400)...Date(timeIntervalSince1970: 1581724799)).contains(Date()) +} diff --git a/submodules/SettingsUI/Sources/SettingsController.swift b/submodules/SettingsUI/Sources/SettingsController.swift index 280b6055f8..e304b7390c 100644 --- a/submodules/SettingsUI/Sources/SettingsController.swift +++ b/submodules/SettingsUI/Sources/SettingsController.swift @@ -17,7 +17,6 @@ import AccountContext import OverlayStatusController import AvatarNode import AlertUI -import PresentationDataUtils import TelegramNotices import GalleryUI import LegacyUI @@ -1436,7 +1435,12 @@ public func settingsController(context: AccountContext, accountManager: AccountM actionsDisposable.dispose() } - let icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") + let icon: UIImage? + if useSpecialTabBarIcons() { + icon = UIImage(bundleImageName: "Chat List/Tabs/Holiday/IconSettings") + } else { + icon = UIImage(bundleImageName: "Chat List/Tabs/IconSettings") + } let notificationsFromAllAccounts = accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) |> map { sharedData -> Bool in diff --git a/submodules/StatisticsUI/BUCK b/submodules/StatisticsUI/BUCK new file mode 100644 index 0000000000..911a9fff4a --- /dev/null +++ b/submodules/StatisticsUI/BUCK @@ -0,0 +1,31 @@ +load("//Config:buck_rule_macros.bzl", "static_library") + +static_library( + name = "StatisticsUI", + srcs = glob([ + "Sources/**/*.swift", + ]), + deps = [ + "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", + "//submodules/AsyncDisplayKit:AsyncDisplayKit#shared", + "//submodules/Display:Display#shared", + "//submodules/Postbox:Postbox#shared", + "//submodules/TelegramCore:TelegramCore#shared", + "//submodules/SyncCore:SyncCore#shared", + "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/TelegramUIPreferences:TelegramUIPreferences", + "//submodules/AccountContext:AccountContext", + "//submodules/ItemListUI:ItemListUI", + "//submodules/AvatarNode:AvatarNode", + "//submodules/TelegramStringFormatting:TelegramStringFormatting", + "//submodules/AlertUI:AlertUI", + "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/TelegramNotices:TelegramNotices", + "//submodules/MergeLists:MergeLists", + "//submodules/Charts:Charts", + ], + frameworks = [ + "$SDKROOT/System/Library/Frameworks/Foundation.framework", + "$SDKROOT/System/Library/Frameworks/UIKit.framework", + ], +) diff --git a/submodules/StatisticsUI/Info.plist b/submodules/StatisticsUI/Info.plist new file mode 100644 index 0000000000..e1fe4cfb7b --- /dev/null +++ b/submodules/StatisticsUI/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + + diff --git a/submodules/StatisticsUI/Sources/StatisticsUI.h b/submodules/StatisticsUI/Sources/StatisticsUI.h new file mode 100644 index 0000000000..89573b3f16 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatisticsUI.h @@ -0,0 +1,19 @@ +// +// StatisticsUI.h +// StatisticsUI +// +// Created by Peter on 8/13/19. +// Copyright © 2019 Telegram Messenger LLP. All rights reserved. +// + +#import + +//! Project version number for StatisticsUI. +FOUNDATION_EXPORT double StatisticsUIVersionNumber; + +//! Project version string for StatisticsUI. +FOUNDATION_EXPORT const unsigned char StatisticsUIVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/submodules/StatisticsUI/Sources/StatsController.swift b/submodules/StatisticsUI/Sources/StatsController.swift new file mode 100644 index 0000000000..440d29cf02 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsController.swift @@ -0,0 +1,351 @@ +import Foundation +import UIKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import SyncCore +import MapKit +import TelegramPresentationData +import TelegramUIPreferences +import ItemListUI +import PresentationDataUtils +import AccountContext +import PresentationDataUtils +import AppBundle +import ContextUI +import TelegramNotices + +private final class StatsArguments { + init() { + } +} + +private enum StatsSection: Int32 { + case overview + case growth + case followers + case notifications + case viewsByHour + case postInteractions + case viewsBySource + case followersBySource + case languages +} + +private enum StatsEntry: ItemListNodeEntry { + case overviewHeader(PresentationTheme, String) + case overview(PresentationTheme, ChannelStats) + + case growthTitle(PresentationTheme, String) + case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case followersTitle(PresentationTheme, String) + case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case notificationsTitle(PresentationTheme, String) + case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case viewsByHourTitle(PresentationTheme, String) + case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case postInteractionsTitle(PresentationTheme, String) + case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case viewsBySourceTitle(PresentationTheme, String) + case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case followersBySourceTitle(PresentationTheme, String) + case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + case languagesTitle(PresentationTheme, String) + case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph) + + var section: ItemListSectionId { + switch self { + case .overviewHeader, .overview: + return StatsSection.overview.rawValue + case .growthTitle, .growthGraph: + return StatsSection.growth.rawValue + case .followersTitle, .followersGraph: + return StatsSection.followers.rawValue + case .notificationsTitle, .notificationsGraph: + return StatsSection.notifications.rawValue + case .viewsByHourTitle, .viewsByHourGraph: + return StatsSection.viewsByHour.rawValue + case .postInteractionsTitle, .postInteractionsGraph: + return StatsSection.postInteractions.rawValue + case .viewsBySourceTitle, .viewsBySourceGraph: + return StatsSection.viewsBySource.rawValue + case .followersBySourceTitle, .followersBySourceGraph: + return StatsSection.followersBySource.rawValue + case .languagesTitle, .languagesGraph: + return StatsSection.languages.rawValue + } + } + + var stableId: Int32 { + switch self { + case .overviewHeader: + return 0 + case .overview: + return 1 + case .growthTitle: + return 2 + case .growthGraph: + return 3 + case .followersTitle: + return 4 + case .followersGraph: + return 5 + case .notificationsTitle: + return 6 + case .notificationsGraph: + return 7 + case .viewsByHourTitle: + return 8 + case .viewsByHourGraph: + return 9 + case .postInteractionsTitle: + return 10 + case .postInteractionsGraph: + return 11 + case .viewsBySourceTitle: + return 12 + case .viewsBySourceGraph: + return 13 + case .followersBySourceTitle: + return 14 + case .followersBySourceGraph: + return 15 + case .languagesTitle: + return 16 + case .languagesGraph: + return 17 + } + } + + static func ==(lhs: StatsEntry, rhs: StatsEntry) -> Bool { + switch lhs { + case let .overviewHeader(lhsTheme, lhsText): + if case let .overviewHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .overview(lhsTheme, lhsStats): + if case let .overview(rhsTheme, rhsStats) = rhs, lhsTheme === rhsTheme, lhsStats == rhsStats { + return true + } else { + return false + } + case let .growthTitle(lhsTheme, lhsText): + if case let .growthTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .growthGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .growthGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .followersTitle(lhsTheme, lhsText): + if case let .followersTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .followersGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .followersGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .notificationsTitle(lhsTheme, lhsText): + if case let .notificationsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .notificationsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .notificationsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .viewsByHourTitle(lhsTheme, lhsText): + if case let .viewsByHourTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .viewsByHourGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .viewsByHourGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .postInteractionsTitle(lhsTheme, lhsText): + if case let .postInteractionsTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .postInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .postInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .viewsBySourceTitle(lhsTheme, lhsText): + if case let .viewsBySourceTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .viewsBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .viewsBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .followersBySourceTitle(lhsTheme, lhsText): + if case let .followersBySourceTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .followersBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .followersBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + case let .languagesTitle(lhsTheme, lhsText): + if case let .languagesTitle(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .languagesGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph): + if case let .languagesGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph { + return true + } else { + return false + } + } + } + + static func <(lhs: StatsEntry, rhs: StatsEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { + switch self { + case let .overviewHeader(theme, text), + let .growthTitle(theme, text), + let .followersTitle(theme, text), + let .notificationsTitle(theme, text), + let .viewsByHourTitle(theme, text), + let .postInteractionsTitle(theme, text), + let .viewsBySourceTitle(theme, text), + let .followersBySourceTitle(theme, text), + let .languagesTitle(theme, text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .overview(theme, stats): + return StatsOverviewItem(presentationData: presentationData, stats: stats, sectionId: self.section, style: .blocks) + case let .growthGraph(theme, strings, dateTimeFormat, title, graph), + let .followersGraph(theme, strings, dateTimeFormat, title, graph), + let .notificationsGraph(theme, strings, dateTimeFormat, title, graph), + let .viewsByHourGraph(theme, strings, dateTimeFormat, title, graph), + let .postInteractionsGraph(theme, strings, dateTimeFormat, title, graph), + let .viewsBySourceGraph(theme, strings, dateTimeFormat, title, graph), + let .followersBySourceGraph(theme, strings, dateTimeFormat, title, graph), + let .languagesGraph(theme, strings, dateTimeFormat, title, graph): + return StatsGraphItem(presentationData: presentationData, title: title, graph: graph, sectionId: self.section, style: .blocks) + } + } +} + +private func statsControllerEntries(data: ChannelStats?, presentationData: PresentationData) -> [StatsEntry] { + var entries: [StatsEntry] = [] + + if let data = data { + entries.append(.overviewHeader(presentationData.theme, "OVERVIEW")) + entries.append(.overview(presentationData.theme, data)) + + entries.append(.growthTitle(presentationData.theme, "GROWTH")) + entries.append(.growthGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Growth", data.growthGraph)) + + entries.append(.followersTitle(presentationData.theme, "FOLLOWERS")) + entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Followers", data.followersGraph)) + + entries.append(.notificationsTitle(presentationData.theme, "NOTIFICATIONS")) + entries.append(.notificationsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Notifications", data.muteGraph)) + } + + return entries +} + +public func channelStatsController(context: AccountContext, peer: Peer, cachedPeerData: CachedPeerData) -> ViewController { + var pushControllerImpl: ((ViewController) -> Void)? + var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var navigateToChatImpl: ((Peer) -> Void)? + + let actionsDisposable = DisposableSet() + let checkCreationAvailabilityDisposable = MetaDisposable() + actionsDisposable.add(checkCreationAvailabilityDisposable) + + let dataPromise = Promise(nil) + + var datacenterId: Int32 = 0 + if let cachedData = cachedPeerData as? CachedChannelData { + datacenterId = cachedData.statsDatacenterId + } + + let statsContext = ChannelStatsContext(network: context.account.network, datacenterId: datacenterId, peer: peer) + let dataSignal: Signal = statsContext.state + |> map { state in + return state.stats + } |> afterNext({ [weak statsContext] a in + if let w = statsContext, let a = a { + if case .OnDemand = a.interactionsGraph { + w.loadInteractionsGraph() + } + } + }) + dataPromise.set(.single(nil) |> then(dataSignal)) + + let arguments = StatsArguments() + + let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get()) + |> deliverOnMainQueue + |> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState, Any)) in + let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChannelInfo_Stats), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: statsControllerEntries(data: data, presentationData: presentationData), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: false) + + return (controllerState, (listState, arguments)) + } + |> afterDisposed { + actionsDisposable.dispose() + let _ = statsContext.state + } + + let controller = ItemListController(context: context, state: signal) + controller.didDisappear = { [weak controller] _ in + controller?.clearItemNodesHighlight(animated: true) + } + pushControllerImpl = { [weak controller] c in + if let controller = controller { + (controller.navigationController as? NavigationController)?.pushViewController(c, animated: true) + } + } + presentControllerImpl = { [weak controller] c, a in + if let controller = controller { + controller.present(c, in: .window(.root), with: a) + } + } + return controller +} diff --git a/submodules/StatisticsUI/Sources/StatsGraphItem.swift b/submodules/StatisticsUI/Sources/StatsGraphItem.swift new file mode 100644 index 0000000000..a800baf8e9 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsGraphItem.swift @@ -0,0 +1,205 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import SyncCore +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import Charts + +class StatsGraphItem: ListViewItem, ItemListItem { + let presentationData: ItemListPresentationData + let title: String + let graph: ChannelStatsGraph + let sectionId: ItemListSectionId + let style: ItemListStyle + + init(presentationData: ItemListPresentationData, title: String, graph: ChannelStatsGraph, sectionId: ItemListSectionId, style: ItemListStyle) { + self.presentationData = presentationData + self.title = title + self.graph = graph + self.sectionId = sectionId + self.style = style + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = StatsGraphItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? StatsGraphItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } + + var selectable: Bool = false +} + +class StatsGraphItemNode: ListViewItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + + let chartNode: ChartNode + + private var item: StatsGraphItem? + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.backgroundColor = .white + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.chartNode = ChartNode() + + super.init(layerBacked: false, dynamicBounce: false) + + self.clipsToBounds = true + + self.addSubnode(self.chartNode) + } + + func asyncLayout() -> (_ item: StatsGraphItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let currentItem = self.item + + return { item, params, neighbors in + let leftInset = params.leftInset + let rightInset: CGFloat = params.rightInset + var updatedTheme: PresentationTheme? + var updatedGraph: ChannelStatsGraph? + + if currentItem?.presentationData.theme !== item.presentationData.theme { + updatedTheme = item.presentationData.theme + } + + if currentItem?.graph != item.graph { + updatedGraph = item.graph + } + + let contentSize: CGSize + let insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + let itemBackgroundColor: UIColor + let itemSeparatorColor: UIColor + + switch item.style { + case .plain: + itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor + contentSize = CGSize(width: params.width, height: 320.0) + insets = itemListNeighborsPlainInsets(neighbors) + case .blocks: + itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor + contentSize = CGSize(width: params.width, height: 320.0) + insets = itemListNeighborsGroupedInsets(neighbors) + } + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + + return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in + if let strongSelf = self { + strongSelf.item = item + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = itemSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor + strongSelf.backgroundNode.backgroundColor = itemBackgroundColor + } + + if let updatedGraph = updatedGraph, case let .Loaded(data) = updatedGraph { + strongSelf.chartNode.setup(data) + } + + switch item.style { + case .plain: + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = leftInset + default: + bottomStripeInset = 0.0 + } + + strongSelf.chartNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -30.0), size: CGSize(width: layout.size.width - leftInset - rightInset, height: 350.0)) + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateAdded(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} + diff --git a/submodules/StatisticsUI/Sources/StatsOverviewItem.swift b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift new file mode 100644 index 0000000000..5e85186e30 --- /dev/null +++ b/submodules/StatisticsUI/Sources/StatsOverviewItem.swift @@ -0,0 +1,292 @@ +import Foundation +import UIKit +import Display +import AsyncDisplayKit +import SwiftSignalKit +import TelegramCore +import SyncCore +import TelegramPresentationData +import ItemListUI +import PresentationDataUtils +import Charts + +class StatsOverviewItem: ListViewItem, ItemListItem { + let presentationData: ItemListPresentationData + let stats: ChannelStats + let sectionId: ItemListSectionId + let style: ItemListStyle + + init(presentationData: ItemListPresentationData, stats: ChannelStats, sectionId: ItemListSectionId, style: ItemListStyle) { + self.presentationData = presentationData + self.stats = stats + self.sectionId = sectionId + self.style = style + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = StatsOverviewItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply() }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? StatsOverviewItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply() + }) + } + } + } + } + } + + var selectable: Bool = false +} + +class StatsOverviewItemNode: ListViewItemNode { + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + + private let followersValueLabel: ImmediateTextNode + private let viewsPerPostValueLabel: ImmediateTextNode + private let sharesPerPostValueLabel: ImmediateTextNode + private let enabledNotificationsValueLabel: ImmediateTextNode + + private let followersTitleLabel: ImmediateTextNode + private let viewsPerPostTitleLabel: ImmediateTextNode + private let sharesPerPostTitleLabel: ImmediateTextNode + private let enabledNotificationsTitleLabel: ImmediateTextNode + + private let followersDeltaLabel: ImmediateTextNode + private let viewsPerPostDeltaLabel: ImmediateTextNode + private let sharesPerPostDeltaLabel: ImmediateTextNode + + private var item: StatsOverviewItem? + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + self.backgroundNode.backgroundColor = .white + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.followersValueLabel = ImmediateTextNode() + self.viewsPerPostValueLabel = ImmediateTextNode() + self.sharesPerPostValueLabel = ImmediateTextNode() + self.enabledNotificationsValueLabel = ImmediateTextNode() + + self.followersTitleLabel = ImmediateTextNode() + self.viewsPerPostTitleLabel = ImmediateTextNode() + self.sharesPerPostTitleLabel = ImmediateTextNode() + self.enabledNotificationsTitleLabel = ImmediateTextNode() + + self.followersDeltaLabel = ImmediateTextNode() + self.viewsPerPostDeltaLabel = ImmediateTextNode() + self.sharesPerPostDeltaLabel = ImmediateTextNode() + + super.init(layerBacked: false, dynamicBounce: false) + + self.clipsToBounds = true + + self.addSubnode(self.followersValueLabel) + self.addSubnode(self.viewsPerPostValueLabel) + self.addSubnode(self.sharesPerPostValueLabel) + self.addSubnode(self.enabledNotificationsValueLabel) + + self.addSubnode(self.followersTitleLabel) + self.addSubnode(self.viewsPerPostTitleLabel) + self.addSubnode(self.sharesPerPostTitleLabel) + self.addSubnode(self.enabledNotificationsTitleLabel) + + self.addSubnode(self.followersDeltaLabel) + self.addSubnode(self.viewsPerPostDeltaLabel) + self.addSubnode(self.sharesPerPostDeltaLabel) + } + + func asyncLayout() -> (_ item: StatsOverviewItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { + let makeFollowersValueLabelLayout = TextNode.asyncLayout(self.followersValueLabel) + let makeViewsPerPostValueLabelLayout = TextNode.asyncLayout(self.viewsPerPostValueLabel) + let makeSharesPerPostValueLabelLayout = TextNode.asyncLayout(self.sharesPerPostValueLabel) + let makeEnabledNotificationsValueLabelLayout = TextNode.asyncLayout(self.enabledNotificationsValueLabel) + + let makeFollowersTitleLabelLayout = TextNode.asyncLayout(self.followersTitleLabel) + let makeViewsPerPostTitleLabelLayout = TextNode.asyncLayout(self.viewsPerPostTitleLabel) + let makeSharesPerPostTitleLabelLayout = TextNode.asyncLayout(self.sharesPerPostTitleLabel) + let makeEnabledNotificationsTitleLabelLayout = TextNode.asyncLayout(self.enabledNotificationsTitleLabel) + + let makeFollowersDeltaLabelLayout = TextNode.asyncLayout(self.followersDeltaLabel) + let makeViewsPerPostDeltaLabelLayout = TextNode.asyncLayout(self.viewsPerPostDeltaLabel) + let makeSharesPerPostDeltaLabelLayout = TextNode.asyncLayout(self.sharesPerPostDeltaLabel) + + let currentItem = self.item + + return { item, params, neighbors in + let leftInset = params.leftInset + let rightInset: CGFloat = params.rightInset + var updatedTheme: PresentationTheme? + var updatedGraph: ChannelStatsGraph? + + if currentItem?.presentationData.theme !== item.presentationData.theme { + updatedTheme = item.presentationData.theme + } + + let valueFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + let deltaFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize) + + let (followersValueLabelLayout, followersValueLabelApply) = makeFollowersValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "221K", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostValueLabelLayout, viewsPerPostValueLabelApply) = makeViewsPerPostValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "120K", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostValueLabelLayout, sharesPerPostValueLabelApply) = makeSharesPerPostValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "350", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (enabledNotificationsValueLabelLayout, enabledNotificationsValueLabelApply) = makeEnabledNotificationsValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "22.77%", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + + let (followersTitleLabelLayout, followersTitleLabelApply) = makeFollowersTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Followers", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostTitleLabelLayout, viewsPerPostTitleLabelApply) = makeViewsPerPostTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Views Per Post", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostTitleLabelLayout, sharesPerPostTitleLabelApply) = makeSharesPerPostTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Shares Per Post", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (enabledNotificationsTitleLabelLayout, enabledNotificationsTitleLabelApply) = makeEnabledNotificationsTitleLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Enabled Notifications", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (followersDeltaLabelLayout, followersDeltaLabelApply) = makeFollowersDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "+474 (0.21%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (viewsPerPostDeltaLabelLayout, viewsPerPostDeltaLabelApply) = makeViewsPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "-14K (10.68%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let (sharesPerPostDeltaLabelLayout, sharesPerPostDeltaLabelApply) = makeSharesPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "-134 (27.68%)", font: valueFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let contentSize: CGSize + let insets: UIEdgeInsets + let separatorHeight = UIScreenPixel + let itemBackgroundColor: UIColor + let itemSeparatorColor: UIColor + + switch item.style { + case .plain: + itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor + contentSize = CGSize(width: params.width, height: 120.0) + insets = itemListNeighborsPlainInsets(neighbors) + case .blocks: + itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor + itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor + contentSize = CGSize(width: params.width, height: 120.0) + insets = itemListNeighborsGroupedInsets(neighbors) + } + + let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + + return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in + if let strongSelf = self { + strongSelf.item = item + + let _ = followersValueLabelApply() + let _ = viewsPerPostValueLabelApply() + let _ = sharesPerPostValueLabelApply() + let _ = enabledNotificationsValueLabelApply() + + let _ = followersTitleLabelApply() + let _ = viewsPerPostTitleLabelApply() + let _ = sharesPerPostTitleLabelApply() + let _ = enabledNotificationsTitleLabelApply() + + let _ = followersDeltaLabelApply() + let _ = viewsPerPostDeltaLabelApply() + let _ = sharesPerPostDeltaLabelApply() + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = itemSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = itemSeparatorColor + strongSelf.backgroundNode.backgroundColor = itemBackgroundColor + } + + switch item.style { + case .plain: + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = leftInset + default: + bottomStripeInset = 0.0 + } + + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + + strongSelf.followersValueLabel.frame = CGRect(origin: CGPoint(x: leftInset, y: 7.0), size: followersValueLabelLayout.size) + + strongSelf.viewsPerPostValueLabel.frame = CGRect(origin: CGPoint(x: leftInset, y: 44.0), size: viewsPerPostValueLabelLayout.size) + + strongSelf.sharesPerPostValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 44.0), size: sharesPerPostValueLabelLayout.size) + + strongSelf.enabledNotificationsValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 7.0), size: enabledNotificationsValueLabelLayout.size) + } + }) + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateAdded(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } +} + diff --git a/submodules/SyncCore/Sources/CachedChannelData.swift b/submodules/SyncCore/Sources/CachedChannelData.swift index c00a913477..49bcb7c71c 100644 --- a/submodules/SyncCore/Sources/CachedChannelData.swift +++ b/submodules/SyncCore/Sources/CachedChannelData.swift @@ -166,6 +166,7 @@ public final class CachedChannelData: CachedPeerData { public let slowModeTimeout: Int32? public let slowModeValidUntilTimestamp: Int32? public let hasScheduledMessages: Bool + public let statsDatacenterId: Int32 public let peerIds: Set public let messageIds: Set @@ -192,9 +193,10 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = nil self.slowModeValidUntilTimestamp = nil self.hasScheduledMessages = false + self.statsDatacenterId = 0 } - public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool) { + public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32) { self.isNotAccessible = isNotAccessible self.flags = flags self.about = about @@ -211,6 +213,7 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = slowModeTimeout self.slowModeValidUntilTimestamp = slowModeValidUntilTimestamp self.hasScheduledMessages = hasScheduledMessages + self.statsDatacenterId = statsDatacenterId var peerIds = Set() for botInfo in botInfos { @@ -231,67 +234,71 @@ public final class CachedChannelData: CachedPeerData { } public func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedAbout(_ about: String?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedSlowModeTimeout(_ slowModeTimeout: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedSlowModeValidUntilTimestamp(_ slowModeValidUntilTimestamp: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId) + } + + public func withUpdatedStatsDatacenterId(_ statsDatacenterId: Int32) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId) } public init(decoder: PostboxDecoder) { @@ -346,6 +353,7 @@ public final class CachedChannelData: CachedPeerData { self.slowModeTimeout = decoder.decodeOptionalInt32ForKey("smt") self.slowModeValidUntilTimestamp = decoder.decodeOptionalInt32ForKey("smv") self.hasScheduledMessages = decoder.decodeBoolForKey("hsm", orElse: false) + self.statsDatacenterId = decoder.decodeInt32ForKey("sdi", orElse: 0) if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { peerIds.insert(linkedDiscussionPeerId) @@ -430,6 +438,7 @@ public final class CachedChannelData: CachedPeerData { encoder.encodeNil(forKey: "smv") } encoder.encodeBool(self.hasScheduledMessages, forKey: "hsm") + encoder.encodeInt32(self.statsDatacenterId, forKey: "sdi") } public func isEqual(to: CachedPeerData) -> Bool { @@ -497,6 +506,14 @@ public final class CachedChannelData: CachedPeerData { return false } + if other.hasScheduledMessages != self.hasScheduledMessages { + return false + } + + if other.statsDatacenterId != self.statsDatacenterId { + return false + } + return true } } diff --git a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift index 79fe68a5ed..e0c3f565a9 100644 --- a/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/SyncCore/Sources/TextEntitiesMessageAttribute.swift @@ -19,6 +19,7 @@ public enum MessageTextEntityType: Equatable { case Strikethrough case BlockQuote case Underline + case BankCard case Custom(type: CustomEntityType) } @@ -65,6 +66,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { self.type = .BlockQuote case 15: self.type = .Underline + case 16: + self.type = .BankCard case Int32.max: self.type = .Custom(type: decoder.decodeInt32ForKey("type", orElse: 0)) default: @@ -110,6 +113,8 @@ public struct MessageTextEntity: PostboxCoding, Equatable { encoder.encodeInt32(14, forKey: "_rawValue") case .Underline: encoder.encodeInt32(15, forKey: "_rawValue") + case .BankCard: + encoder.encodeInt32(16, forKey: "_rawValue") case let .Custom(type): encoder.encodeInt32(Int32.max, forKey: "_rawValue") encoder.encodeInt32(type, forKey: "type") diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index ab2f4a7b7b..be3e05a869 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -412,6 +412,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2103482845] = { return Api.SecurePlainData.parse_securePlainPhone($0) } dict[569137759] = { return Api.SecurePlainData.parse_securePlainEmail($0) } dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) } + dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) } + dict[-1092839390] = { return Api.StatsGraph.parse_statsGraphError($0) } + dict[-1057809608] = { return Api.StatsGraph.parse_statsGraph($0) } dict[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) } dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) } dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($0) } @@ -480,6 +483,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-668391402] = { return Api.InputUser.parse_inputUser($0) } dict[-1366746132] = { return Api.Page.parse_page($0) } dict[871426631] = { return Api.SecureCredentialsEncrypted.parse_secureCredentialsEncrypted($0) } + dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) } dict[157948117] = { return Api.upload.File.parse_file($0) } dict[-242427324] = { return Api.upload.File.parse_fileCdnRedirect($0) } dict[-1078612597] = { return Api.ChannelLocation.parse_channelLocationEmpty($0) } @@ -506,6 +510,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1160215659] = { return Api.InputMessage.parse_inputMessageReplyTo($0) } dict[-2037963464] = { return Api.InputMessage.parse_inputMessagePinned($0) } dict[-1564789301] = { return Api.PhoneCallProtocol.parse_phoneCallProtocol($0) } + dict[-1237848657] = { return Api.StatsDateRangeDays.parse_statsDateRangeDays($0) } dict[-1567175714] = { return Api.MessageFwdAuthor.parse_messageFwdAuthor($0) } dict[-1539849235] = { return Api.WallPaper.parse_wallPaper($0) } dict[-1963717851] = { return Api.WallPaper.parse_wallPaperNoFile($0) } @@ -520,6 +525,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($0) } + dict[205195937] = { return Api.stats.BroadcastStats.parse_broadcastStats($0) } dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) } dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) } dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($0) } @@ -527,6 +533,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1918567619] = { return Api.Updates.parse_updatesCombined($0) } dict[1957577280] = { return Api.Updates.parse_updates($0) } dict[301019932] = { return Api.Updates.parse_updateShortSentMessage($0) } + dict[-884757282] = { return Api.StatsAbsValueAndPrev.parse_statsAbsValueAndPrev($0) } dict[1038967584] = { return Api.MessageMedia.parse_messageMediaEmpty($0) } dict[1457575028] = { return Api.MessageMedia.parse_messageMediaGeo($0) } dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) } @@ -608,6 +615,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1421174295] = { return Api.WebPageAttribute.parse_webPageAttributeTheme($0) } dict[82699215] = { return Api.messages.FeaturedStickers.parse_featuredStickersNotModified($0) } dict[-123893531] = { return Api.messages.FeaturedStickers.parse_featuredStickers($0) } + dict[1375940666] = { return Api.auth.LoginTokenInfo.parse_loginTokenInfo($0) } dict[-2048646399] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonMissed($0) } dict[-527056480] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonDisconnect($0) } dict[1471006352] = { return Api.PhoneCallDiscardReason.parse_phoneCallDiscardReasonHangup($0) } @@ -678,8 +686,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) } dict[-302170017] = { return Api.messages.AllStickers.parse_allStickers($0) } dict[-1655957568] = { return Api.PhoneConnection.parse_phoneConnection($0) } - dict[-206688531] = { return Api.help.UserInfo.parse_userInfoEmpty($0) } - dict[32192344] = { return Api.help.UserInfo.parse_userInfo($0) } dict[-1194283041] = { return Api.AccountDaysTTL.parse_accountDaysTTL($0) } dict[-1658158621] = { return Api.SecureValueType.parse_secureValueTypePersonalDetails($0) } dict[1034709504] = { return Api.SecureValueType.parse_secureValueTypePassport($0) } @@ -746,6 +752,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1363483106] = { return Api.DialogPeer.parse_dialogPeerFolder($0) } dict[-104284986] = { return Api.WebDocument.parse_webDocumentNoProxy($0) } dict[475467473] = { return Api.WebDocument.parse_webDocument($0) } + dict[1211967244] = { return Api.Theme.parse_themeDocumentNotModified($0) } dict[42930452] = { return Api.Theme.parse_theme($0) } dict[-1290580579] = { return Api.contacts.Found.parse_found($0) } dict[-368018716] = { return Api.ChannelAdminLogEventsFilter.parse_channelAdminLogEventsFilter($0) } @@ -761,6 +768,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($0) } + dict[-581804346] = { return Api.StatsRowAbsValueAndPrev.parse_statsRowAbsValueAndPrev($0) } dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) } dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) } dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) } @@ -782,6 +790,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1672577397] = { return Api.MessageEntity.parse_messageEntityUnderline($0) } dict[-1090087980] = { return Api.MessageEntity.parse_messageEntityStrike($0) } dict[34469328] = { return Api.MessageEntity.parse_messageEntityBlockquote($0) } + dict[1981704948] = { return Api.MessageEntity.parse_messageEntityBankCard($0) } dict[483901197] = { return Api.InputPhoto.parse_inputPhotoEmpty($0) } dict[1001634122] = { return Api.InputPhoto.parse_inputPhoto($0) } dict[-567906571] = { return Api.contacts.TopPeers.parse_topPeersNotModified($0) } @@ -799,11 +808,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-94974410] = { return Api.EncryptedChat.parse_encryptedChat($0) } dict[332848423] = { return Api.EncryptedChat.parse_encryptedChatDiscarded($0) } dict[-901375139] = { return Api.PeerLocated.parse_peerLocated($0) } + dict[-118740917] = { return Api.PeerLocated.parse_peerSelfLocated($0) } dict[922273905] = { return Api.Document.parse_documentEmpty($0) } dict[-1683841855] = { return Api.Document.parse_document($0) } dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) } dict[-892779534] = { return Api.WebAuthorization.parse_webAuthorization($0) } dict[-805141448] = { return Api.ImportedContact.parse_importedContact($0) } + dict[-419239361] = { return Api.payments.BankCardData.parse_bankCardData($0) } return dict }() @@ -1081,6 +1092,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.AffectedHistory: _1.serialize(buffer, boxed) + case let _1 as Api.StatsGraph: + _1.serialize(buffer, boxed) case let _1 as Api.account.PasswordInputSettings: _1.serialize(buffer, boxed) case let _1 as Api.PageTableCell: @@ -1151,6 +1164,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.SecureCredentialsEncrypted: _1.serialize(buffer, boxed) + case let _1 as Api.StatsPercentValue: + _1.serialize(buffer, boxed) case let _1 as Api.upload.File: _1.serialize(buffer, boxed) case let _1 as Api.ChannelLocation: @@ -1185,6 +1200,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallProtocol: _1.serialize(buffer, boxed) + case let _1 as Api.StatsDateRangeDays: + _1.serialize(buffer, boxed) case let _1 as Api.MessageFwdAuthor: _1.serialize(buffer, boxed) case let _1 as Api.WallPaper: @@ -1201,8 +1218,12 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PaymentCharge: _1.serialize(buffer, boxed) + case let _1 as Api.stats.BroadcastStats: + _1.serialize(buffer, boxed) case let _1 as Api.Updates: _1.serialize(buffer, boxed) + case let _1 as Api.StatsAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.MessageMedia: _1.serialize(buffer, boxed) case let _1 as Api.PaymentSavedCredentials: @@ -1273,6 +1294,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.messages.FeaturedStickers: _1.serialize(buffer, boxed) + case let _1 as Api.auth.LoginTokenInfo: + _1.serialize(buffer, boxed) case let _1 as Api.PhoneCallDiscardReason: _1.serialize(buffer, boxed) case let _1 as Api.NearestDc: @@ -1331,8 +1354,6 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.PhoneConnection: _1.serialize(buffer, boxed) - case let _1 as Api.help.UserInfo: - _1.serialize(buffer, boxed) case let _1 as Api.AccountDaysTTL: _1.serialize(buffer, boxed) case let _1 as Api.SecureValueType: @@ -1381,6 +1402,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.updates.ChannelDifference: _1.serialize(buffer, boxed) + case let _1 as Api.StatsRowAbsValueAndPrev: + _1.serialize(buffer, boxed) case let _1 as Api.channels.AdminLogResults: _1.serialize(buffer, boxed) case let _1 as Api.ChatOnlines: @@ -1409,6 +1432,8 @@ public struct Api { _1.serialize(buffer, boxed) case let _1 as Api.ImportedContact: _1.serialize(buffer, boxed) + case let _1 as Api.payments.BankCardData: + _1.serialize(buffer, boxed) default: break } diff --git a/submodules/TelegramApi/Sources/Api1.swift b/submodules/TelegramApi/Sources/Api1.swift index 9e6d38f6d1..09dc6c09b6 100644 --- a/submodules/TelegramApi/Sources/Api1.swift +++ b/submodules/TelegramApi/Sources/Api1.swift @@ -11956,6 +11956,82 @@ public extension Api { } } + } + public enum StatsGraph: TypeConstructorDescription { + case statsGraphAsync(token: String) + case statsGraphError(error: String) + case statsGraph(json: Api.DataJSON) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsGraphAsync(let token): + if boxed { + buffer.appendInt32(1244130093) + } + serializeString(token, buffer: buffer, boxed: false) + break + case .statsGraphError(let error): + if boxed { + buffer.appendInt32(-1092839390) + } + serializeString(error, buffer: buffer, boxed: false) + break + case .statsGraph(let json): + if boxed { + buffer.appendInt32(-1057809608) + } + json.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsGraphAsync(let token): + return ("statsGraphAsync", [("token", token)]) + case .statsGraphError(let error): + return ("statsGraphError", [("error", error)]) + case .statsGraph(let json): + return ("statsGraph", [("json", json)]) + } + } + + public static func parse_statsGraphAsync(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphAsync(token: _1!) + } + else { + return nil + } + } + public static func parse_statsGraphError(_ reader: BufferReader) -> StatsGraph? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraphError(error: _1!) + } + else { + return nil + } + } + public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? { + var _1: Api.DataJSON? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.DataJSON + } + let _c1 = _1 != nil + if _c1 { + return Api.StatsGraph.statsGraph(json: _1!) + } + else { + return nil + } + } + } public enum PageTableCell: TypeConstructorDescription { case pageTableCell(flags: Int32, text: Api.RichText?, colspan: Int32?, rowspan: Int32?) @@ -13662,6 +13738,44 @@ public extension Api { } } + } + public enum StatsPercentValue: TypeConstructorDescription { + case statsPercentValue(part: Double, total: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsPercentValue(let part, let total): + if boxed { + buffer.appendInt32(-875679776) + } + serializeDouble(part, buffer: buffer, boxed: false) + serializeDouble(total, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsPercentValue(let part, let total): + return ("statsPercentValue", [("part", part), ("total", total)]) + } + } + + public static func parse_statsPercentValue(_ reader: BufferReader) -> StatsPercentValue? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsPercentValue.statsPercentValue(part: _1!, total: _2!) + } + else { + return nil + } + } + } public enum ChannelLocation: TypeConstructorDescription { case channelLocationEmpty @@ -14434,6 +14548,44 @@ public extension Api { } } + } + public enum StatsDateRangeDays: TypeConstructorDescription { + case statsDateRangeDays(minDate: Int32, maxDate: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + if boxed { + buffer.appendInt32(-1237848657) + } + serializeInt32(minDate, buffer: buffer, boxed: false) + serializeInt32(maxDate, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsDateRangeDays(let minDate, let maxDate): + return ("statsDateRangeDays", [("minDate", minDate), ("maxDate", maxDate)]) + } + } + + public static func parse_statsDateRangeDays(_ reader: BufferReader) -> StatsDateRangeDays? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsDateRangeDays.statsDateRangeDays(minDate: _1!, maxDate: _2!) + } + else { + return nil + } + } + } public enum MessageFwdAuthor: TypeConstructorDescription { case messageFwdAuthor(channelId: Int32) @@ -15098,6 +15250,44 @@ public extension Api { } } + } + public enum StatsAbsValueAndPrev: TypeConstructorDescription { + case statsAbsValueAndPrev(current: Double, previous: Double) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + if boxed { + buffer.appendInt32(-884757282) + } + serializeDouble(current, buffer: buffer, boxed: false) + serializeDouble(previous, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsAbsValueAndPrev(let current, let previous): + return ("statsAbsValueAndPrev", [("current", current), ("previous", previous)]) + } + } + + public static func parse_statsAbsValueAndPrev(_ reader: BufferReader) -> StatsAbsValueAndPrev? { + var _1: Double? + _1 = reader.readDouble() + var _2: Double? + _2 = reader.readDouble() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StatsAbsValueAndPrev.statsAbsValueAndPrev(current: _1!, previous: _2!) + } + else { + return nil + } + } + } public enum MessageMedia: TypeConstructorDescription { case messageMediaEmpty @@ -20448,10 +20638,17 @@ public extension Api { } public enum Theme: TypeConstructorDescription { + case themeDocumentNotModified case theme(flags: Int32, id: Int64, accessHash: Int64, slug: String, title: String, document: Api.Document?, settings: Api.ThemeSettings?, installsCount: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { + case .themeDocumentNotModified: + if boxed { + buffer.appendInt32(1211967244) + } + + break case .theme(let flags, let id, let accessHash, let slug, let title, let document, let settings, let installsCount): if boxed { buffer.appendInt32(42930452) @@ -20470,11 +20667,16 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { + case .themeDocumentNotModified: + return ("themeDocumentNotModified", []) case .theme(let flags, let id, let accessHash, let slug, let title, let document, let settings, let installsCount): return ("theme", [("flags", flags), ("id", id), ("accessHash", accessHash), ("slug", slug), ("title", title), ("document", document), ("settings", settings), ("installsCount", installsCount)]) } } + public static func parse_themeDocumentNotModified(_ reader: BufferReader) -> Theme? { + return Api.Theme.themeDocumentNotModified + } public static func parse_theme(_ reader: BufferReader) -> Theme? { var _1: Int32? _1 = reader.readInt32() @@ -20880,6 +21082,54 @@ public extension Api { } } + } + public enum StatsRowAbsValueAndPrev: TypeConstructorDescription { + case statsRowAbsValueAndPrev(id: String, title: String, shortTitle: String, values: Api.StatsAbsValueAndPrev) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + if boxed { + buffer.appendInt32(-581804346) + } + serializeString(id, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(shortTitle, buffer: buffer, boxed: false) + values.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .statsRowAbsValueAndPrev(let id, let title, let shortTitle, let values): + return ("statsRowAbsValueAndPrev", [("id", id), ("title", title), ("shortTitle", shortTitle), ("values", values)]) + } + } + + public static func parse_statsRowAbsValueAndPrev(_ reader: BufferReader) -> StatsRowAbsValueAndPrev? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.StatsRowAbsValueAndPrev.statsRowAbsValueAndPrev(id: _1!, title: _2!, shortTitle: _3!, values: _4!) + } + else { + return nil + } + } + } public enum ChatOnlines: TypeConstructorDescription { case chatOnlines(onlines: Int32) @@ -20982,6 +21232,7 @@ public extension Api { case messageEntityUnderline(offset: Int32, length: Int32) case messageEntityStrike(offset: Int32, length: Int32) case messageEntityBlockquote(offset: Int32, length: Int32) + case messageEntityBankCard(offset: Int32, length: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21115,6 +21366,13 @@ public extension Api { serializeInt32(offset, buffer: buffer, boxed: false) serializeInt32(length, buffer: buffer, boxed: false) break + case .messageEntityBankCard(let offset, let length): + if boxed { + buffer.appendInt32(1981704948) + } + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(length, buffer: buffer, boxed: false) + break } } @@ -21156,6 +21414,8 @@ public extension Api { return ("messageEntityStrike", [("offset", offset), ("length", length)]) case .messageEntityBlockquote(let offset, let length): return ("messageEntityBlockquote", [("offset", offset), ("length", length)]) + case .messageEntityBankCard(let offset, let length): + return ("messageEntityBankCard", [("offset", offset), ("length", length)]) } } @@ -21425,6 +21685,20 @@ public extension Api { return nil } } + public static func parse_messageEntityBankCard(_ reader: BufferReader) -> MessageEntity? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.MessageEntity.messageEntityBankCard(offset: _1!, length: _2!) + } + else { + return nil + } + } } public enum InputPhoto: TypeConstructorDescription { @@ -21727,6 +22001,7 @@ public extension Api { } public enum PeerLocated: TypeConstructorDescription { case peerLocated(peer: Api.Peer, expires: Int32, distance: Int32) + case peerSelfLocated(expires: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21738,6 +22013,12 @@ public extension Api { serializeInt32(expires, buffer: buffer, boxed: false) serializeInt32(distance, buffer: buffer, boxed: false) break + case .peerSelfLocated(let expires): + if boxed { + buffer.appendInt32(-118740917) + } + serializeInt32(expires, buffer: buffer, boxed: false) + break } } @@ -21745,6 +22026,8 @@ public extension Api { switch self { case .peerLocated(let peer, let expires, let distance): return ("peerLocated", [("peer", peer), ("expires", expires), ("distance", distance)]) + case .peerSelfLocated(let expires): + return ("peerSelfLocated", [("expires", expires)]) } } @@ -21767,6 +22050,17 @@ public extension Api { return nil } } + public static func parse_peerSelfLocated(_ reader: BufferReader) -> PeerLocated? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.PeerLocated.peerSelfLocated(expires: _1!) + } + else { + return nil + } + } } public enum Document: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index f0cb6195e9..4f499c6615 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -490,6 +490,176 @@ public struct payments { } } + public enum BankCardData: TypeConstructorDescription { + case bankCardData(flags: Int32, title: String, url: String?, urlName: String?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .bankCardData(let flags, let title, let url, let urlName): + if boxed { + buffer.appendInt32(-419239361) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(url!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 0) != 0 {serializeString(urlName!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .bankCardData(let flags, let title, let url, let urlName): + return ("bankCardData", [("flags", flags), ("title", title), ("url", url), ("urlName", urlName)]) + } + } + + public static func parse_bankCardData(_ reader: BufferReader) -> BankCardData? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) } + var _4: String? + if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.payments.BankCardData.bankCardData(flags: _1!, title: _2!, url: _3, urlName: _4) + } + else { + return nil + } + } + + } +} +} +public extension Api { +public struct stats { + public enum BroadcastStats: TypeConstructorDescription { + case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, viewsBySource: [Api.StatsRowAbsValueAndPrev], newFollowersBySource: [Api.StatsRowAbsValueAndPrev], languages: [Api.StatsRowAbsValueAndPrev], growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + if boxed { + buffer.appendInt32(205195937) + } + period.serialize(buffer, true) + followers.serialize(buffer, true) + viewsPerPost.serialize(buffer, true) + sharesPerPost.serialize(buffer, true) + enabledNotifications.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(viewsBySource.count)) + for item in viewsBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(newFollowersBySource.count)) + for item in newFollowersBySource { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(languages.count)) + for item in languages { + item.serialize(buffer, true) + } + growthGraph.serialize(buffer, true) + followersGraph.serialize(buffer, true) + muteGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + interactionsGraph.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let viewsBySource, let newFollowersBySource, let languages, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph): + return ("broadcastStats", [("period", period), ("followers", followers), ("viewsPerPost", viewsPerPost), ("sharesPerPost", sharesPerPost), ("enabledNotifications", enabledNotifications), ("viewsBySource", viewsBySource), ("newFollowersBySource", newFollowersBySource), ("languages", languages), ("growthGraph", growthGraph), ("followersGraph", followersGraph), ("muteGraph", muteGraph), ("topHoursGraph", topHoursGraph), ("interactionsGraph", interactionsGraph)]) + } + } + + public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsPercentValue? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue + } + var _6: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _7: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _8: [Api.StatsRowAbsValueAndPrev]? + if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self) + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { + return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, viewsBySource: _6!, newFollowersBySource: _7!, languages: _8!, growthGraph: _9!, followersGraph: _10!, muteGraph: _11!, topHoursGraph: _12!, interactionsGraph: _13!) + } + else { + return nil + } + } + + } } } public extension Api { @@ -859,6 +1029,76 @@ public struct auth { return Api.auth.CodeType.codeTypeFlashCall } + } + public enum LoginTokenInfo: TypeConstructorDescription { + case loginTokenInfo(dcId: Int32, authKeyId: Int64, deviceModel: String, platform: String, systemVersion: String, apiId: Int32, appName: String, appVersion: String, ip: String, region: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .loginTokenInfo(let dcId, let authKeyId, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let ip, let region): + if boxed { + buffer.appendInt32(1375940666) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeInt64(authKeyId, buffer: buffer, boxed: false) + serializeString(deviceModel, buffer: buffer, boxed: false) + serializeString(platform, buffer: buffer, boxed: false) + serializeString(systemVersion, buffer: buffer, boxed: false) + serializeInt32(apiId, buffer: buffer, boxed: false) + serializeString(appName, buffer: buffer, boxed: false) + serializeString(appVersion, buffer: buffer, boxed: false) + serializeString(ip, buffer: buffer, boxed: false) + serializeString(region, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .loginTokenInfo(let dcId, let authKeyId, let deviceModel, let platform, let systemVersion, let apiId, let appName, let appVersion, let ip, let region): + return ("loginTokenInfo", [("dcId", dcId), ("authKeyId", authKeyId), ("deviceModel", deviceModel), ("platform", platform), ("systemVersion", systemVersion), ("apiId", apiId), ("appName", appName), ("appVersion", appVersion), ("ip", ip), ("region", region)]) + } + } + + public static func parse_loginTokenInfo(_ reader: BufferReader) -> LoginTokenInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) + var _5: String? + _5 = parseString(reader) + var _6: Int32? + _6 = reader.readInt32() + var _7: String? + _7 = parseString(reader) + var _8: String? + _8 = parseString(reader) + var _9: String? + _9 = parseString(reader) + var _10: String? + _10 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 { + return Api.auth.LoginTokenInfo.loginTokenInfo(dcId: _1!, authKeyId: _2!, deviceModel: _3!, platform: _4!, systemVersion: _5!, apiId: _6!, appName: _7!, appVersion: _8!, ip: _9!, region: _10!) + } + else { + return nil + } + } + } public enum SentCodeType: TypeConstructorDescription { case sentCodeTypeApp(length: Int32) @@ -1859,70 +2099,6 @@ public struct help { } } - } - public enum UserInfo: TypeConstructorDescription { - case userInfoEmpty - case userInfo(message: String, entities: [Api.MessageEntity], author: String, date: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .userInfoEmpty: - if boxed { - buffer.appendInt32(-206688531) - } - - break - case .userInfo(let message, let entities, let author, let date): - if boxed { - buffer.appendInt32(32192344) - } - serializeString(message, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities.count)) - for item in entities { - item.serialize(buffer, true) - } - serializeString(author, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .userInfoEmpty: - return ("userInfoEmpty", []) - case .userInfo(let message, let entities, let author, let date): - return ("userInfo", [("message", message), ("entities", entities), ("author", author), ("date", date)]) - } - } - - public static func parse_userInfoEmpty(_ reader: BufferReader) -> UserInfo? { - return Api.help.UserInfo.userInfoEmpty - } - public static func parse_userInfo(_ reader: BufferReader) -> UserInfo? { - var _1: String? - _1 = parseString(reader) - var _2: [Api.MessageEntity]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) - } - var _3: String? - _3 = parseString(reader) - var _4: Int32? - _4 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.help.UserInfo.userInfo(message: _1!, entities: _2!, author: _3!, date: _4!) - } - else { - return nil - } - } - } public enum TermsOfServiceUpdate: TypeConstructorDescription { case termsOfServiceUpdateEmpty(expires: Int32) diff --git a/submodules/TelegramApi/Sources/Api3.swift b/submodules/TelegramApi/Sources/Api3.swift index 74e4884bf6..aee22f1e04 100644 --- a/submodules/TelegramApi/Sources/Api3.swift +++ b/submodules/TelegramApi/Sources/Api3.swift @@ -3196,6 +3196,25 @@ public extension Api { }) } + public static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1257951254) + serializeInt32(flags, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stickersets.count)) + for item in stickersets { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.toggleStickerSets", parameters: [("flags", flags), ("stickersets", stickersets)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + public static func getPollVotes(flags: Int32, peer: Api.InputPeer, id: Int32, option: Buffer?, offset: String?, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(-1200736242) @@ -3885,6 +3904,50 @@ public extension Api { return result }) } + + public static func getBankCardData(number: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(779736953) + serializeString(number, buffer: buffer, boxed: false) + return (FunctionDescription(name: "payments.getBankCardData", parameters: [("number", number)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.BankCardData? in + let reader = BufferReader(buffer) + var result: Api.payments.BankCardData? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.payments.BankCardData + } + return result + }) + } + } + public struct stats { + public static func getBroadcastStats(flags: Int32, channel: Api.InputChannel) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1421720550) + serializeInt32(flags, buffer: buffer, boxed: false) + channel.serialize(buffer, true) + return (FunctionDescription(name: "stats.getBroadcastStats", parameters: [("flags", flags), ("channel", channel)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.BroadcastStats? in + let reader = BufferReader(buffer) + var result: Api.stats.BroadcastStats? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stats.BroadcastStats + } + return result + }) + } + + public static func loadAsyncGraph(token: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1749505346) + serializeString(token, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("token", token)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in + let reader = BufferReader(buffer) + var result: Api.StatsGraph? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + return result + }) + } } public struct auth { public static func checkPhone(phoneNumber: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { @@ -4558,11 +4621,13 @@ public extension Api { }) } - public static func getLocated(geoPoint: Api.InputGeoPoint) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + public static func getLocated(flags: Int32, geoPoint: Api.InputGeoPoint, selfExpires: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(171270230) + buffer.appendInt32(-750207932) + serializeInt32(flags, buffer: buffer, boxed: false) geoPoint.serialize(buffer, true) - return (FunctionDescription(name: "contacts.getLocated", parameters: [("geoPoint", geoPoint)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(selfExpires!, buffer: buffer, boxed: false)} + return (FunctionDescription(name: "contacts.getLocated", parameters: [("flags", flags), ("geoPoint", geoPoint), ("selfExpires", selfExpires)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -4815,40 +4880,6 @@ public extension Api { return result }) } - - public static func editUserInfo(userId: Api.InputUser, message: String, entities: [Api.MessageEntity]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(1723407216) - userId.serialize(buffer, true) - serializeString(message, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities.count)) - for item in entities { - item.serialize(buffer, true) - } - return (FunctionDescription(name: "help.editUserInfo", parameters: [("userId", userId), ("message", message), ("entities", entities)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.UserInfo? in - let reader = BufferReader(buffer) - var result: Api.help.UserInfo? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.help.UserInfo - } - return result - }) - } - - public static func getUserInfo(userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(59377875) - userId.serialize(buffer, true) - return (FunctionDescription(name: "help.getUserInfo", parameters: [("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.help.UserInfo? in - let reader = BufferReader(buffer) - var result: Api.help.UserInfo? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.help.UserInfo - } - return result - }) - } } public struct updates { public static func getState() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift index ad168e7d01..4e870b88ce 100644 --- a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift @@ -1295,8 +1295,13 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo } case let .updatePeerLocated(peers): var peersNearby: [PeerNearby] = [] - for case let .peerLocated(peer, expires, distance) in peers { - peersNearby.append(PeerNearby(id: peer.peerId, expires: expires, distance: distance)) + for peer in peers { + switch peer { + case let .peerLocated(peer, expires, distance): + peersNearby.append(.peer(id: peer.peerId, expires: expires, distance: distance)) + case let .peerSelfLocated(expires): + peersNearby.append(.selfPeer(expires: expires)) + } } updatedState.updatePeersNearby(peersNearby) case let .updateNewScheduledMessage(apiMessage): diff --git a/submodules/TelegramCore/Sources/BankCards.swift b/submodules/TelegramCore/Sources/BankCards.swift new file mode 100644 index 0000000000..f0db9d6304 --- /dev/null +++ b/submodules/TelegramCore/Sources/BankCards.swift @@ -0,0 +1,34 @@ +import Foundation +import Postbox +import TelegramApi +import SyncCore +import SwiftSignalKit + +public struct BankCardInfo { + public let title: String + public let url: String? + public let actionTitle: String? +} + +public func getBankCardInfo(account: Account, cardNumber: String) -> Signal { + return account.network.request(Api.functions.payments.getBankCardData(number: cardNumber)) + |> map { result -> BankCardInfo? in + return BankCardInfo(apiBankCardData: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +extension BankCardInfo { + init(apiBankCardData: Api.payments.BankCardData) { + switch apiBankCardData { + case let .bankCardData(flags, title, url, urlName): + self.title = title + self.url = url + self.actionTitle = urlName + } + } +} + + diff --git a/submodules/TelegramCore/Sources/ChannelStatistics.swift b/submodules/TelegramCore/Sources/ChannelStatistics.swift new file mode 100644 index 0000000000..1e501b535b --- /dev/null +++ b/submodules/TelegramCore/Sources/ChannelStatistics.swift @@ -0,0 +1,424 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramApi +import MtProtoKit +import SyncCore + +public struct ChannelStatsDateRange: Equatable { + public let minDate: Int32 + public let maxDate: Int32 +} + +public struct ChannelStatsValue: Equatable { + public let current: Double + public let previous: Double +} + +public struct ChannelStatsPercentValue: Equatable { + public let fraction: Double + public let total: Double +} + +public struct ChannelStatsNamedValue: Equatable { + public let id: String + public let title: String + public let shortTitle: String + public let value: ChannelStatsValue +} + +public enum ChannelStatsGraph: Equatable { + case OnDemand(token: String) + case Failed(error: String) + case Loaded(data: String) +} + +public final class ChannelStats: Equatable { + public let period: ChannelStatsDateRange + public let followers: ChannelStatsValue + public let viewsPerPost: ChannelStatsValue + public let sharesPerPost: ChannelStatsValue + public let enabledNotifications: ChannelStatsPercentValue + public let viewsBySource: [ChannelStatsNamedValue] + public let newFollowersBySource: [ChannelStatsNamedValue] + public let languages: [ChannelStatsNamedValue] + public let growthGraph: ChannelStatsGraph + public let followersGraph: ChannelStatsGraph + public let muteGraph: ChannelStatsGraph + public let topHoursGraph: ChannelStatsGraph + public let interactionsGraph: ChannelStatsGraph + + public init(period: ChannelStatsDateRange, followers: ChannelStatsValue, viewsPerPost: ChannelStatsValue, sharesPerPost: ChannelStatsValue, enabledNotifications: ChannelStatsPercentValue, viewsBySource: [ChannelStatsNamedValue], newFollowersBySource: [ChannelStatsNamedValue], languages: [ChannelStatsNamedValue], growthGraph: ChannelStatsGraph, followersGraph: ChannelStatsGraph, muteGraph: ChannelStatsGraph, topHoursGraph: ChannelStatsGraph, interactionsGraph: ChannelStatsGraph) { + self.period = period + self.followers = followers + self.viewsPerPost = viewsPerPost + self.sharesPerPost = sharesPerPost + self.enabledNotifications = enabledNotifications + self.viewsBySource = viewsBySource + self.newFollowersBySource = newFollowersBySource + self.languages = languages + self.growthGraph = growthGraph + self.followersGraph = followersGraph + self.muteGraph = muteGraph + self.topHoursGraph = topHoursGraph + self.interactionsGraph = interactionsGraph + } + + public static func == (lhs: ChannelStats, rhs: ChannelStats) -> Bool { + if lhs.period != rhs.period { + return false + } + if lhs.followers != rhs.followers { + return false + } + if lhs.viewsPerPost != rhs.viewsPerPost { + return false + } + if lhs.sharesPerPost != rhs.sharesPerPost { + return false + } + if lhs.enabledNotifications != rhs.enabledNotifications { + return false + } + if lhs.viewsBySource != rhs.viewsBySource { + return false + } + if lhs.newFollowersBySource != rhs.newFollowersBySource { + return false + } + if lhs.languages != rhs.languages { + return false + } + if lhs.growthGraph != rhs.growthGraph { + return false + } + if lhs.followersGraph != rhs.followersGraph { + return false + } + if lhs.muteGraph != rhs.muteGraph { + return false + } + if lhs.topHoursGraph != rhs.topHoursGraph { + return false + } + if lhs.interactionsGraph != rhs.interactionsGraph { + return false + } + return true + } + + public func withUpdatedGrowthGraph(_ growthGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedFollowersGraph(_ followersGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedMuteGraph(_ muteGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedTopHoursGraph(_ viewsByHourGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: viewsByHourGraph, interactionsGraph: self.interactionsGraph) + } + + public func withUpdatedInteractionsGraph(_ interactionsGraph: ChannelStatsGraph) -> ChannelStats { + return ChannelStats(period: self.period, followers: self.followers, viewsPerPost: self.viewsPerPost, sharesPerPost: self.sharesPerPost, enabledNotifications: self.enabledNotifications, viewsBySource: self.viewsBySource, newFollowersBySource: self.newFollowersBySource, languages: self.languages, growthGraph: self.growthGraph, followersGraph: self.followersGraph, muteGraph: self.muteGraph, topHoursGraph: self.topHoursGraph, interactionsGraph: interactionsGraph) + } +} + +public struct ChannelStatsContextState: Equatable { + public var stats: ChannelStats? +} + +private func requestStats(network: Network, datacenterId: Int32, peer: Peer, dark: Bool = false) -> Signal { + guard let inputChannel = apiInputChannel(peer) else { + return .never() + } + + var flags: Int32 = 0 + if dark { + flags |= (1 << 1) + } + + let signal: Signal + if network.datacenterId != datacenterId { + signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil) + |> castError(MTRpcError.self) + |> mapToSignal { worker in + return worker.request(Api.functions.stats.getBroadcastStats(flags: flags, channel: inputChannel)) + } + } else { + signal = network.request(Api.functions.stats.getBroadcastStats(flags: flags, channel: inputChannel)) + } + + return signal + |> map { result -> ChannelStats? in + return ChannelStats(apiBroadcastStats: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +private func requestGraph(network: Network, datacenterId: Int32, token: String) -> Signal { + let signal: Signal + if network.datacenterId != datacenterId { + signal = network.download(datacenterId: Int(datacenterId), isMedia: false, tag: nil) + |> castError(MTRpcError.self) + |> mapToSignal { worker in + return worker.request(Api.functions.stats.loadAsyncGraph(token: token)) + } + } else { + signal = network.request(Api.functions.stats.loadAsyncGraph(token: token)) + } + + return signal + |> map { result -> ChannelStatsGraph? in + return ChannelStatsGraph(apiStatsGraph: result) + } + |> `catch` { _ -> Signal in + return .single(nil) + } +} + +private final class ChannelStatsContextImpl { + private let network: Network + private let peer: Peer + private let datacenterId: Int32 + + private var _state: ChannelStatsContextState { + didSet { + if self._state != oldValue { + self._statePromise.set(.single(self._state)) + } + } + } + private let _statePromise = Promise() + var state: Signal { + return self._statePromise.get() + } + + private let disposable = MetaDisposable() + private let disposables = DisposableDict() + + init(network: Network, datacenterId: Int32, peer: Peer) { + assert(Queue.mainQueue().isCurrent()) + + self.network = network + self.peer = peer + self.datacenterId = datacenterId + self._state = ChannelStatsContextState(stats: nil) + self._statePromise.set(.single(self._state)) + + self.load() + } + + deinit { + assert(Queue.mainQueue().isCurrent()) + self.disposable.dispose() + self.disposables.dispose() + } + + private func load() { + assert(Queue.mainQueue().isCurrent()) + + self.disposable.set((requestStats(network: self.network, datacenterId: self.datacenterId, peer: self.peer) + |> deliverOnMainQueue).start(next: { [weak self] stats in + if let strongSelf = self { + strongSelf._state = ChannelStatsContextState(stats: stats) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + })) + } + + func loadGrowthGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.growthGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedGrowthGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadFollowersGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.followersGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedFollowersGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadMuteGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.muteGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedMuteGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadTopHoursGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.topHoursGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedTopHoursGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } + + func loadInteractionsGraph() { + guard let stats = self._state.stats else { + return + } + if case let .OnDemand(token) = stats.interactionsGraph { + self.disposables.set((requestGraph(network: self.network, datacenterId: self.datacenterId, token: token) + |> deliverOnMainQueue).start(next: { [weak self] graph in + if let strongSelf = self, let graph = graph { + strongSelf._state = ChannelStatsContextState(stats: strongSelf._state.stats?.withUpdatedInteractionsGraph(graph)) + strongSelf._statePromise.set(.single(strongSelf._state)) + } + }), forKey: token) + } + } +} + +public final class ChannelStatsContext { + private let impl: QueueLocalObject + + public var state: Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.state.start(next: { value in + subscriber.putNext(value) + })) + } + return disposable + } + } + + public init(network: Network, datacenterId: Int32, peer: Peer) { + self.impl = QueueLocalObject(queue: Queue.mainQueue(), generate: { + return ChannelStatsContextImpl(network: network, datacenterId: datacenterId, peer: peer) + }) + } + + public func loadGrowthGraph() { + self.impl.with { impl in + impl.loadGrowthGraph() + } + } + + public func loadFollowersGraph() { + self.impl.with { impl in + impl.loadFollowersGraph() + } + } + + public func loadMuteGraph() { + self.impl.with { impl in + impl.loadMuteGraph() + } + } + + public func loadTopHoursGraph() { + self.impl.with { impl in + impl.loadTopHoursGraph() + } + } + + public func loadInteractionsGraph() { + self.impl.with { impl in + impl.loadInteractionsGraph() + } + } +} + +extension ChannelStatsGraph { + init(apiStatsGraph: Api.StatsGraph) { + switch apiStatsGraph { + case let .statsGraph(json): + if case let .dataJSON(string) = json { + self = .Loaded(data: string) + } else { + self = .Failed(error: "") + } + case let .statsGraphError(error): + self = .Failed(error: error) + case let .statsGraphAsync(token): + self = .OnDemand(token: token) + } + } +} + +extension ChannelStatsDateRange { + init(apiStatsDateRangeDays: Api.StatsDateRangeDays) { + switch apiStatsDateRangeDays { + case let .statsDateRangeDays(minDate, maxDate): + self = ChannelStatsDateRange(minDate: minDate, maxDate: maxDate) + } + } +} + +extension ChannelStatsValue { + init(apiStatsAbsValueAndPrev: Api.StatsAbsValueAndPrev) { + switch apiStatsAbsValueAndPrev { + case let .statsAbsValueAndPrev(current, previous): + self = ChannelStatsValue(current: current, previous: previous) + } + } +} + +extension ChannelStatsNamedValue { + init(apiStatsRowAbsValueAndPrev: Api.StatsRowAbsValueAndPrev) { + switch apiStatsRowAbsValueAndPrev { + case let .statsRowAbsValueAndPrev(id, title, shortTitle, values): + self = ChannelStatsNamedValue(id: id, title: title, shortTitle: shortTitle, value: ChannelStatsValue(apiStatsAbsValueAndPrev: values)) + } + } +} + +extension ChannelStatsPercentValue { + init(apiPercentValue: Api.StatsPercentValue) { + switch apiPercentValue { + case let .statsPercentValue(part, total): + self = ChannelStatsPercentValue(fraction: part, total: total) + } + } +} + +extension ChannelStats { + convenience init(apiBroadcastStats: Api.stats.BroadcastStats) { + switch apiBroadcastStats { + case let .broadcastStats(period, followers, viewsPerPost, sharesPerPost, enabledNotifications, viewsBySource, newFollowersBySource, languages, growthGraph, followersGraph, muteGraph, topHoursGraph, interactionsGraph): + self.init(period: ChannelStatsDateRange(apiStatsDateRangeDays: period), followers: ChannelStatsValue(apiStatsAbsValueAndPrev: followers), viewsPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: viewsPerPost), sharesPerPost: ChannelStatsValue(apiStatsAbsValueAndPrev: sharesPerPost), enabledNotifications: ChannelStatsPercentValue(apiPercentValue: enabledNotifications), viewsBySource: viewsBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, newFollowersBySource: newFollowersBySource.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, languages: languages.map { ChannelStatsNamedValue(apiStatsRowAbsValueAndPrev: $0) }, growthGraph: ChannelStatsGraph(apiStatsGraph: growthGraph), followersGraph: ChannelStatsGraph(apiStatsGraph: followersGraph), muteGraph: ChannelStatsGraph(apiStatsGraph: muteGraph), topHoursGraph: ChannelStatsGraph(apiStatsGraph: topHoursGraph), interactionsGraph: ChannelStatsGraph(apiStatsGraph: interactionsGraph)) + } + } +} diff --git a/submodules/TelegramCore/Sources/JSON.swift b/submodules/TelegramCore/Sources/JSON.swift index 556085328b..43dd62bebd 100644 --- a/submodules/TelegramCore/Sources/JSON.swift +++ b/submodules/TelegramCore/Sources/JSON.swift @@ -28,8 +28,7 @@ extension JSON { } } self = .array(values) - } - else if let value = object as? String { + } else if let value = object as? String { self = .string(value) } else if let value = object as? Int { self = .number(Double(value)) diff --git a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift index 7754b00b97..d490602165 100644 --- a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift @@ -676,6 +676,8 @@ private func decryptedEntities73(_ entities: [MessageTextEntity]?) -> [SecretApi break case .Underline: break + case .BankCard: + break case .Custom: break } @@ -723,6 +725,8 @@ private func decryptedEntities101(_ entities: [MessageTextEntity]?) -> [SecretAp result.append(.messageEntityBlockquote(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) case .Underline: result.append(.messageEntityUnderline(offset: Int32(entity.range.lowerBound), length: Int32(entity.range.count))) + case .BankCard: + break case .Custom: break } diff --git a/submodules/TelegramCore/Sources/PeersNearby.swift b/submodules/TelegramCore/Sources/PeersNearby.swift index b872ec5837..4ea533867d 100644 --- a/submodules/TelegramCore/Sources/PeersNearby.swift +++ b/submodules/TelegramCore/Sources/PeersNearby.swift @@ -7,12 +7,57 @@ import SyncCore private typealias SignalKitTimer = SwiftSignalKit.Timer +public enum PeerNearby { + case selfPeer(expires: Int32) + case peer(id: PeerId, expires: Int32, distance: Int32) + + var expires: Int32 { + switch self { + case let .selfPeer(expires), let .peer(_, expires, _): + return expires + } + } +} +public enum PeerNearbyVisibilityUpdate { + case visible(latitude: Double, longitude: Double) + case location(latitude: Double, longitude: Double) + case invisible +} -public struct PeerNearby { - public let id: PeerId - public let expires: Int32 - public let distance: Int32 +public func peersNearbyUpdateVisibility(network: Network, stateManager: AccountStateManager, update: PeerNearbyVisibilityUpdate, background: Bool) -> Signal { + var flags: Int32 = 0 + var geoPoint: Api.InputGeoPoint + var selfExpires: Int32? + + switch update { + case let .visible(latitude, longitude): + flags |= (1 << 0) + geoPoint = .inputGeoPoint(lat: latitude, long: longitude) + selfExpires = 86400 + case let .location(latitude, longitude): + geoPoint = .inputGeoPoint(lat: latitude, long: longitude) + case .invisible: + flags |= (1 << 0) + geoPoint = .inputGeoPointEmpty + selfExpires = 0 + } + + if background { + flags |= (1 << 1) + } + + return network.request(Api.functions.contacts.getLocated(flags: flags, geoPoint: geoPoint, selfExpires: selfExpires)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + stateManager.addUpdates(updates) + } + return .complete() + } } public final class PeersNearbyContext { @@ -23,10 +68,10 @@ public final class PeersNearbyContext { private var entries: [PeerNearby]? - public init(network: Network, accountStateManager: AccountStateManager, coordinate: (latitude: Double, longitude: Double)) { + public init(network: Network, stateManager: AccountStateManager, coordinate: (latitude: Double, longitude: Double)) { let expiryExtension: Double = 10.0 - let poll = network.request(Api.functions.contacts.getLocated(geoPoint: .inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude))) + let poll = network.request(Api.functions.contacts.getLocated(flags: 0, geoPoint: .inputGeoPoint(lat: coordinate.latitude, long: coordinate.longitude), selfExpires: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -39,23 +84,28 @@ public final class PeersNearbyContext { case let .updates(updates, _, _, _, _): for update in updates { if case let .updatePeerLocated(peers) = update { - for case let .peerLocated(peer, expires, distance) in peers { - peersNearby.append(PeerNearby(id: peer.peerId, expires: expires, distance: distance)) + for peer in peers { + switch peer { + case let .peerLocated(peer, expires, distance): + peersNearby.append(.peer(id: peer.peerId, expires: expires, distance: distance)) + case let .peerSelfLocated(expires): + peersNearby.append(.selfPeer(expires: expires)) + } } } } default: break } - accountStateManager.addUpdates(updates) + stateManager.addUpdates(updates) } return .single(peersNearby) |> then( - accountStateManager.updatedPeersNearby() + stateManager.updatedPeersNearby() |> castError(Void.self) ) } - + let error: Signal = .single(Void()) |> then(Signal.fail(Void()) |> suspendAwareDelay(25.0, queue: self.queue)) let combined = combineLatest(poll, error) |> map { data, _ -> [PeerNearby] in @@ -77,18 +127,37 @@ public final class PeersNearbyContext { let updatedEntries = updatedEntries.filter { Double($0.expires) + expiryExtension > timestamp } var existingPeerIds: [PeerId: Int] = [:] + var existingSelfPeer: Int? for i in 0 ..< entries.count { - existingPeerIds[entries[i].id] = i + if case let .peer(id, _, _) = entries[i] { + existingPeerIds[id] = i + } else if case .selfPeer = entries[i] { + existingSelfPeer = i + } } + var selfPeer: PeerNearby? for entry in updatedEntries { - if let index = existingPeerIds[entry.id] { - entries[index] = entry - } else { - entries.append(entry) + switch entry { + case let .selfPeer: + if let index = existingSelfPeer { + entries[index] = entry + } else { + selfPeer = entry + } + case let .peer(id, _, _): + if let index = existingPeerIds[id] { + entries[index] = entry + } else { + entries.append(entry) + } } } + if let peer = selfPeer { + entries.insert(peer, at: 0) + } + strongSelf.entries = entries for subscriber in strongSelf.subscribers.copyItems() { subscriber(strongSelf.entries) diff --git a/submodules/TelegramCore/Sources/Serialization.swift b/submodules/TelegramCore/Sources/Serialization.swift index 02470ccbac..15b20dd3d8 100644 --- a/submodules/TelegramCore/Sources/Serialization.swift +++ b/submodules/TelegramCore/Sources/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 109 + return 110 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift index d5c0b31029..44751ce910 100644 --- a/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/StoreMessage_Telegram.swift @@ -386,6 +386,8 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .Strikethrough)) case let .messageEntityBlockquote(offset, length): result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BlockQuote)) + case let .messageEntityBankCard(offset, length): + result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .BankCard)) } } return result diff --git a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift index c898bed30f..1702002184 100644 --- a/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/TextEntitiesMessageAttribute.swift @@ -45,6 +45,8 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa apiEntities.append(.messageEntityBlockquote(offset: offset, length: length)) case .Underline: apiEntities.append(.messageEntityUnderline(offset: offset, length: length)) + case .BankCard: + apiEntities.append(.messageEntityBankCard(offset: offset, length: length)) case .Custom: break } diff --git a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift index 1050b92be7..d0f10bfb51 100644 --- a/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/UpdateCachedPeerData.swift @@ -450,6 +450,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI .withUpdatedSlowModeTimeout(slowmodeSeconds) .withUpdatedSlowModeValidUntilTimestamp(slowmodeNextSendDate) .withUpdatedHasScheduledMessages(hasScheduledMessages) +// .withUpdatedStatsDatacenterId(statsDc ?? 0) }) if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated { diff --git a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift index f55acaf222..188fb8bab7 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationStrings.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationStrings.swift @@ -334,4899 +334,4909 @@ public final class PresentationStrings: Equatable { public var SettingsSearch_Synonyms_EditProfile_Username: String { return self._s[136]! } public var Group_Username_InvalidStartsWithNumber: String { return self._s[137]! } public var UserInfo_NotificationsEnabled: String { return self._s[138]! } - public var Map_Search: String { return self._s[139]! } - public var ClearCache_StorageFree: String { return self._s[141]! } - public var Login_TermsOfServiceHeader: String { return self._s[142]! } + public var PeopleNearby_MakeVisibleDescription: String { return self._s[139]! } + public var Map_Search: String { return self._s[140]! } + public var ClearCache_StorageFree: String { return self._s[142]! } + public var Login_TermsOfServiceHeader: String { return self._s[143]! } public func Notification_PinnedVideoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[143]!, self._r[143]!, [_0]) + return formatWithArgumentRanges(self._s[144]!, self._r[144]!, [_0]) } public func Channel_AdminLog_MessageToggleSignaturesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[145]!, self._r[145]!, [_0]) + return formatWithArgumentRanges(self._s[146]!, self._r[146]!, [_0]) } - public var Wallet_Sent_Title: String { return self._s[146]! } - public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[147]! } - public var Weekday_Today: String { return self._s[148]! } + public var Wallet_Sent_Title: String { return self._s[147]! } + public var TwoStepAuth_SetupPasswordConfirmPassword: String { return self._s[148]! } + public var Weekday_Today: String { return self._s[149]! } public func InstantPage_AuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[150]!, self._r[150]!, [_1, _2]) + return formatWithArgumentRanges(self._s[151]!, self._r[151]!, [_1, _2]) } public func Conversation_MessageDialogRetryAll(_ _1: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[151]!, self._r[151]!, ["\(_1)"]) + return formatWithArgumentRanges(self._s[152]!, self._r[152]!, ["\(_1)"]) } - public var Notification_PassportValuePersonalDetails: String { return self._s[153]! } - public var Channel_AdminLog_MessagePreviousLink: String { return self._s[154]! } - public var ChangePhoneNumberNumber_NewNumber: String { return self._s[155]! } - public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[156]! } - public var TwoStepAuth_ChangePasswordDescription: String { return self._s[157]! } - public var PhotoEditor_BlurToolLinear: String { return self._s[158]! } - public var Contacts_PermissionsAllowInSettings: String { return self._s[159]! } - public var Weekday_ShortMonday: String { return self._s[160]! } - public var Cache_KeepMedia: String { return self._s[161]! } - public var Passport_FieldIdentitySelfieHelp: String { return self._s[162]! } + public var Notification_PassportValuePersonalDetails: String { return self._s[154]! } + public var Channel_AdminLog_MessagePreviousLink: String { return self._s[155]! } + public var ChangePhoneNumberNumber_NewNumber: String { return self._s[156]! } + public var ApplyLanguage_LanguageNotSupportedError: String { return self._s[157]! } + public var TwoStepAuth_ChangePasswordDescription: String { return self._s[158]! } + public var PhotoEditor_BlurToolLinear: String { return self._s[159]! } + public var Contacts_PermissionsAllowInSettings: String { return self._s[160]! } + public var Weekday_ShortMonday: String { return self._s[161]! } + public var Cache_KeepMedia: String { return self._s[162]! } + public var Passport_FieldIdentitySelfieHelp: String { return self._s[163]! } public func PUSH_PINNED_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[163]!, self._r[163]!, [_1, _2]) + return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_1, _2]) } public func Chat_SlowmodeTooltip(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[164]!, self._r[164]!, [_0]) + return formatWithArgumentRanges(self._s[165]!, self._r[165]!, [_0]) } - public var Wallet_Receive_ShareUrlInfo: String { return self._s[165]! } - public var Conversation_ClousStorageInfo_Description4: String { return self._s[166]! } - public var Wallet_RestoreFailed_Title: String { return self._s[167]! } - public var Passport_Language_ru: String { return self._s[168]! } + public var Wallet_Receive_ShareUrlInfo: String { return self._s[166]! } + public var Conversation_ClousStorageInfo_Description4: String { return self._s[167]! } + public var Wallet_RestoreFailed_Title: String { return self._s[168]! } + public var Passport_Language_ru: String { return self._s[169]! } public func Notification_CreatedChatWithTitle(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[169]!, self._r[169]!, [_0, _1]) + return formatWithArgumentRanges(self._s[170]!, self._r[170]!, [_0, _1]) } - public var WallpaperPreview_PatternIntensity: String { return self._s[170]! } - public var WebBrowser_InAppSafari: String { return self._s[173]! } - public var TwoStepAuth_RecoveryUnavailable: String { return self._s[174]! } - public var EnterPasscode_TouchId: String { return self._s[175]! } - public var PhotoEditor_QualityVeryHigh: String { return self._s[178]! } - public var Checkout_NewCard_SaveInfo: String { return self._s[180]! } - public var Gif_NoGifsPlaceholder: String { return self._s[182]! } + public var WallpaperPreview_PatternIntensity: String { return self._s[171]! } + public var WebBrowser_InAppSafari: String { return self._s[174]! } + public var TwoStepAuth_RecoveryUnavailable: String { return self._s[175]! } + public var EnterPasscode_TouchId: String { return self._s[176]! } + public var PhotoEditor_QualityVeryHigh: String { return self._s[179]! } + public var Checkout_NewCard_SaveInfo: String { return self._s[181]! } + public var Gif_NoGifsPlaceholder: String { return self._s[183]! } public func Notification_InvitedMultiple(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[184]!, self._r[184]!, [_0, _1]) + return formatWithArgumentRanges(self._s[185]!, self._r[185]!, [_0, _1]) } - public var ChatSettings_AutoDownloadEnabled: String { return self._s[185]! } - public var NetworkUsageSettings_BytesSent: String { return self._s[186]! } - public var Checkout_PasswordEntry_Pay: String { return self._s[187]! } - public var AuthSessions_TerminateSession: String { return self._s[188]! } - public var Message_File: String { return self._s[189]! } - public var MediaPicker_VideoMuteDescription: String { return self._s[190]! } - public var SocksProxySetup_ProxyStatusConnected: String { return self._s[191]! } - public var TwoStepAuth_RecoveryCode: String { return self._s[192]! } - public var EnterPasscode_EnterCurrentPasscode: String { return self._s[193]! } + public var ChatSettings_AutoDownloadEnabled: String { return self._s[186]! } + public var NetworkUsageSettings_BytesSent: String { return self._s[187]! } + public var Checkout_PasswordEntry_Pay: String { return self._s[188]! } + public var AuthSessions_TerminateSession: String { return self._s[189]! } + public var Message_File: String { return self._s[190]! } + public var MediaPicker_VideoMuteDescription: String { return self._s[191]! } + public var SocksProxySetup_ProxyStatusConnected: String { return self._s[192]! } + public var TwoStepAuth_RecoveryCode: String { return self._s[193]! } + public var EnterPasscode_EnterCurrentPasscode: String { return self._s[194]! } public func TwoStepAuth_EnterPasswordHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[194]!, self._r[194]!, [_0]) + return formatWithArgumentRanges(self._s[195]!, self._r[195]!, [_0]) } - public var Conversation_Moderate_Report: String { return self._s[196]! } - public var TwoStepAuth_EmailInvalid: String { return self._s[197]! } - public var Passport_Language_ms: String { return self._s[198]! } - public var Channel_Edit_AboutItem: String { return self._s[200]! } - public var DialogList_SearchSectionGlobal: String { return self._s[204]! } - public var AttachmentMenu_WebSearch: String { return self._s[205]! } - public var PasscodeSettings_TurnPasscodeOn: String { return self._s[206]! } - public var Channel_BanUser_Title: String { return self._s[207]! } - public var WallpaperPreview_SwipeTopText: String { return self._s[208]! } - public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[209]! } - public var ArchivedChats_IntroText2: String { return self._s[210]! } - public var Conversation_OpenBotLinkTitle: String { return self._s[211]! } - public var ChatSearch_SearchPlaceholder: String { return self._s[213]! } - public var Notification_Exceptions_DeleteAll: String { return self._s[214]! } - public var Passport_FieldAddressTranslationHelp: String { return self._s[215]! } - public var NotificationsSound_Aurora: String { return self._s[216]! } + public var Conversation_Moderate_Report: String { return self._s[197]! } + public var TwoStepAuth_EmailInvalid: String { return self._s[198]! } + public var Passport_Language_ms: String { return self._s[199]! } + public var Channel_Edit_AboutItem: String { return self._s[201]! } + public var DialogList_SearchSectionGlobal: String { return self._s[205]! } + public var AttachmentMenu_WebSearch: String { return self._s[206]! } + public var PasscodeSettings_TurnPasscodeOn: String { return self._s[207]! } + public var Channel_BanUser_Title: String { return self._s[208]! } + public var WallpaperPreview_SwipeTopText: String { return self._s[209]! } + public var ChatList_DeleteSavedMessagesConfirmationText: String { return self._s[210]! } + public var ArchivedChats_IntroText2: String { return self._s[211]! } + public var Conversation_OpenBotLinkTitle: String { return self._s[212]! } + public var ChatSearch_SearchPlaceholder: String { return self._s[214]! } + public var Notification_Exceptions_DeleteAll: String { return self._s[215]! } + public var Passport_FieldAddressTranslationHelp: String { return self._s[216]! } + public var NotificationsSound_Aurora: String { return self._s[217]! } public func Channel_AdminLog_MessageTransferedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[217]!, self._r[217]!, [_1, _2]) + return formatWithArgumentRanges(self._s[218]!, self._r[218]!, [_1, _2]) } public func FileSize_GB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[218]!, self._r[218]!, [_0]) + return formatWithArgumentRanges(self._s[219]!, self._r[219]!, [_0]) } - public var AuthSessions_LoggedInWithTelegram: String { return self._s[221]! } + public var AuthSessions_LoggedInWithTelegram: String { return self._s[222]! } public func Privacy_GroupsAndChannels_InviteToGroupError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[222]!, self._r[222]!, [_0, _1]) + return formatWithArgumentRanges(self._s[223]!, self._r[223]!, [_0, _1]) } - public var Passport_PasswordNext: String { return self._s[223]! } - public var Bot_GroupStatusReadsHistory: String { return self._s[224]! } - public var EmptyGroupInfo_Line2: String { return self._s[225]! } - public var VoiceOver_Chat_SeenByRecipients: String { return self._s[226]! } - public var Settings_FAQ_Intro: String { return self._s[229]! } - public var PrivacySettings_PasscodeAndTouchId: String { return self._s[231]! } - public var FeaturedStickerPacks_Title: String { return self._s[232]! } - public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[234]! } - public var Username_Title: String { return self._s[235]! } + public var Passport_PasswordNext: String { return self._s[224]! } + public var Bot_GroupStatusReadsHistory: String { return self._s[225]! } + public var EmptyGroupInfo_Line2: String { return self._s[226]! } + public var VoiceOver_Chat_SeenByRecipients: String { return self._s[227]! } + public var Settings_FAQ_Intro: String { return self._s[230]! } + public var PrivacySettings_PasscodeAndTouchId: String { return self._s[232]! } + public var FeaturedStickerPacks_Title: String { return self._s[233]! } + public var TwoStepAuth_PasswordRemoveConfirmation: String { return self._s[235]! } + public var Username_Title: String { return self._s[236]! } public func Message_StickerText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[236]!, self._r[236]!, [_0]) + return formatWithArgumentRanges(self._s[237]!, self._r[237]!, [_0]) } - public var PasscodeSettings_AlphanumericCode: String { return self._s[237]! } - public var Localization_LanguageOther: String { return self._s[238]! } - public var Stickers_SuggestStickers: String { return self._s[239]! } + public var PasscodeSettings_AlphanumericCode: String { return self._s[238]! } + public var Localization_LanguageOther: String { return self._s[239]! } + public var Stickers_SuggestStickers: String { return self._s[240]! } public func Channel_AdminLog_MessageRemovedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[240]!, self._r[240]!, [_0]) + return formatWithArgumentRanges(self._s[241]!, self._r[241]!, [_0]) } - public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[241]! } - public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[242]! } - public var Conversation_DefaultRestrictedStickers: String { return self._s[243]! } + public var NotificationSettings_ShowNotificationsFromAccountsSection: String { return self._s[242]! } + public var Channel_AdminLogFilter_EventsAdmins: String { return self._s[243]! } + public var Conversation_DefaultRestrictedStickers: String { return self._s[244]! } public func Notification_PinnedDeletedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[244]!, self._r[244]!, [_0]) + return formatWithArgumentRanges(self._s[245]!, self._r[245]!, [_0]) } - public var Wallet_TransactionInfo_CopyAddress: String { return self._s[246]! } - public var Group_UpgradeConfirmation: String { return self._s[247]! } - public var DialogList_Unpin: String { return self._s[248]! } - public var Passport_Identity_DateOfBirth: String { return self._s[249]! } - public var Month_ShortOctober: String { return self._s[250]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[251]! } - public var TwoFactorSetup_Done_Text: String { return self._s[252]! } - public var Notification_CallCanceledShort: String { return self._s[253]! } - public var Conversation_StopQuiz: String { return self._s[254]! } - public var Passport_Phone_Help: String { return self._s[255]! } - public var Passport_Language_az: String { return self._s[257]! } - public var CreatePoll_TextPlaceholder: String { return self._s[259]! } - public var VoiceOver_Chat_AnonymousPoll: String { return self._s[260]! } - public var Passport_Identity_DocumentNumber: String { return self._s[261]! } - public var PhotoEditor_CurvesRed: String { return self._s[262]! } - public var PhoneNumberHelp_Alert: String { return self._s[264]! } - public var SocksProxySetup_Port: String { return self._s[265]! } - public var Checkout_PayNone: String { return self._s[266]! } - public var AutoDownloadSettings_WiFi: String { return self._s[267]! } - public var GroupInfo_GroupType: String { return self._s[268]! } - public var StickerSettings_ContextHide: String { return self._s[269]! } - public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[270]! } - public var Group_Setup_HistoryTitle: String { return self._s[272]! } - public var Passport_Identity_FilesUploadNew: String { return self._s[273]! } - public var PasscodeSettings_AutoLock: String { return self._s[274]! } - public var Passport_Title: String { return self._s[275]! } - public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[276]! } - public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[277]! } - public var GroupPermission_NoSendGifs: String { return self._s[278]! } - public var PrivacySettings_PasscodeOn: String { return self._s[279]! } + public var Wallet_TransactionInfo_CopyAddress: String { return self._s[247]! } + public var Group_UpgradeConfirmation: String { return self._s[248]! } + public var DialogList_Unpin: String { return self._s[249]! } + public var Passport_Identity_DateOfBirth: String { return self._s[250]! } + public var Month_ShortOctober: String { return self._s[251]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsSync: String { return self._s[252]! } + public var TwoFactorSetup_Done_Text: String { return self._s[253]! } + public var Notification_CallCanceledShort: String { return self._s[254]! } + public var Conversation_StopQuiz: String { return self._s[255]! } + public var Passport_Phone_Help: String { return self._s[256]! } + public var Passport_Language_az: String { return self._s[258]! } + public var CreatePoll_TextPlaceholder: String { return self._s[260]! } + public var VoiceOver_Chat_AnonymousPoll: String { return self._s[261]! } + public var Passport_Identity_DocumentNumber: String { return self._s[262]! } + public var PhotoEditor_CurvesRed: String { return self._s[263]! } + public var PhoneNumberHelp_Alert: String { return self._s[265]! } + public var SocksProxySetup_Port: String { return self._s[266]! } + public var Checkout_PayNone: String { return self._s[267]! } + public var AutoDownloadSettings_WiFi: String { return self._s[268]! } + public var GroupInfo_GroupType: String { return self._s[269]! } + public var StickerSettings_ContextHide: String { return self._s[270]! } + public var Passport_Address_OneOfTypeTemporaryRegistration: String { return self._s[271]! } + public var Group_Setup_HistoryTitle: String { return self._s[273]! } + public var Passport_Identity_FilesUploadNew: String { return self._s[274]! } + public var PasscodeSettings_AutoLock: String { return self._s[275]! } + public var Passport_Title: String { return self._s[276]! } + public var VoiceOver_Chat_ContactPhoneNumber: String { return self._s[277]! } + public var Channel_AdminLogFilter_EventsNewSubscribers: String { return self._s[278]! } + public var GroupPermission_NoSendGifs: String { return self._s[279]! } + public var PrivacySettings_PasscodeOn: String { return self._s[280]! } public func Conversation_ScheduleMessage_SendTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[280]!, self._r[280]!, [_0]) + return formatWithArgumentRanges(self._s[281]!, self._r[281]!, [_0]) } - public var State_WaitingForNetwork: String { return self._s[283]! } + public var State_WaitingForNetwork: String { return self._s[284]! } public func Notification_Invited(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[284]!, self._r[284]!, [_0, _1]) + return formatWithArgumentRanges(self._s[285]!, self._r[285]!, [_0, _1]) } - public var Calls_NotNow: String { return self._s[286]! } + public var Calls_NotNow: String { return self._s[287]! } public func Channel_DiscussionGroup_HeaderSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[287]!, self._r[287]!, [_0]) + return formatWithArgumentRanges(self._s[288]!, self._r[288]!, [_0]) } - public var UserInfo_SendMessage: String { return self._s[288]! } - public var TwoStepAuth_PasswordSet: String { return self._s[289]! } - public var Passport_DeleteDocument: String { return self._s[290]! } - public var SocksProxySetup_AddProxyTitle: String { return self._s[291]! } + public var UserInfo_SendMessage: String { return self._s[289]! } + public var TwoStepAuth_PasswordSet: String { return self._s[290]! } + public var Passport_DeleteDocument: String { return self._s[291]! } + public var SocksProxySetup_AddProxyTitle: String { return self._s[292]! } public func PUSH_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[292]!, self._r[292]!, [_1]) + return formatWithArgumentRanges(self._s[293]!, self._r[293]!, [_1]) } - public var AuthSessions_AddedDeviceTitle: String { return self._s[293]! } - public var GroupRemoved_Remove: String { return self._s[294]! } - public var Passport_FieldIdentity: String { return self._s[295]! } - public var Group_Setup_TypePrivateHelp: String { return self._s[296]! } - public var Conversation_Processing: String { return self._s[299]! } - public var Wallet_Settings_BackupWallet: String { return self._s[301]! } - public var ChatSettings_AutoPlayAnimations: String { return self._s[302]! } - public var AuthSessions_LogOutApplicationsHelp: String { return self._s[305]! } - public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[306]! } - public var Month_GenFebruary: String { return self._s[307]! } - public var Wallet_Send_NetworkErrorTitle: String { return self._s[308]! } + public var AuthSessions_AddedDeviceTitle: String { return self._s[294]! } + public var GroupRemoved_Remove: String { return self._s[295]! } + public var Passport_FieldIdentity: String { return self._s[296]! } + public var Group_Setup_TypePrivateHelp: String { return self._s[297]! } + public var Conversation_Processing: String { return self._s[300]! } + public var Wallet_Settings_BackupWallet: String { return self._s[302]! } + public var ChatSettings_AutoPlayAnimations: String { return self._s[303]! } + public var AuthSessions_LogOutApplicationsHelp: String { return self._s[306]! } + public var Forward_ErrorPublicQuizDisabledInChannels: String { return self._s[307]! } + public var Month_GenFebruary: String { return self._s[308]! } + public var Wallet_Send_NetworkErrorTitle: String { return self._s[309]! } public func Login_InvalidPhoneEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[310]!, self._r[310]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[311]!, self._r[311]!, [_1, _2, _3, _4, _5]) } - public var Passport_Identity_TypeIdentityCard: String { return self._s[311]! } - public var Wallet_Month_ShortJune: String { return self._s[313]! } - public var AutoDownloadSettings_DataUsageMedium: String { return self._s[314]! } - public var GroupInfo_AddParticipant: String { return self._s[315]! } - public var KeyCommand_SendMessage: String { return self._s[316]! } - public var VoiceOver_Chat_YourContact: String { return self._s[318]! } - public var Map_LiveLocationShowAll: String { return self._s[319]! } - public var WallpaperSearch_ColorOrange: String { return self._s[321]! } - public var Appearance_AppIconDefaultX: String { return self._s[322]! } - public var Checkout_Receipt_Title: String { return self._s[323]! } - public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[324]! } - public var WallpaperPreview_PreviewTopText: String { return self._s[325]! } - public var Message_Contact: String { return self._s[326]! } - public var Call_StatusIncoming: String { return self._s[327]! } - public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[328]! } + public var Passport_Identity_TypeIdentityCard: String { return self._s[312]! } + public var Wallet_Month_ShortJune: String { return self._s[314]! } + public var AutoDownloadSettings_DataUsageMedium: String { return self._s[315]! } + public var GroupInfo_AddParticipant: String { return self._s[316]! } + public var KeyCommand_SendMessage: String { return self._s[317]! } + public var VoiceOver_Chat_YourContact: String { return self._s[319]! } + public var Map_LiveLocationShowAll: String { return self._s[320]! } + public var WallpaperSearch_ColorOrange: String { return self._s[322]! } + public var Appearance_AppIconDefaultX: String { return self._s[323]! } + public var Checkout_Receipt_Title: String { return self._s[324]! } + public var Group_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[325]! } + public var WallpaperPreview_PreviewTopText: String { return self._s[326]! } + public var Message_Contact: String { return self._s[327]! } + public var Call_StatusIncoming: String { return self._s[328]! } + public var Wallet_TransactionInfo_StorageFeeInfo: String { return self._s[329]! } public func Channel_AdminLog_MessageKickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[329]!, self._r[329]!, [_1]) + return formatWithArgumentRanges(self._s[330]!, self._r[330]!, [_1]) } public func PUSH_ENCRYPTED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[331]!, self._r[331]!, [_1]) + return formatWithArgumentRanges(self._s[332]!, self._r[332]!, [_1]) } - public var VoiceOver_Media_PlaybackRate: String { return self._s[332]! } - public var Passport_FieldIdentityDetailsHelp: String { return self._s[333]! } - public var Conversation_ViewChannel: String { return self._s[334]! } + public var VoiceOver_Media_PlaybackRate: String { return self._s[333]! } + public var Passport_FieldIdentityDetailsHelp: String { return self._s[334]! } + public var Conversation_ViewChannel: String { return self._s[335]! } public func Time_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[335]!, self._r[335]!, [_0]) + return formatWithArgumentRanges(self._s[336]!, self._r[336]!, [_0]) } - public var Theme_Colors_Accent: String { return self._s[336]! } - public var Passport_Language_nl: String { return self._s[338]! } - public var Camera_Retake: String { return self._s[339]! } + public var Theme_Colors_Accent: String { return self._s[337]! } + public var Passport_Language_nl: String { return self._s[339]! } + public var Camera_Retake: String { return self._s[340]! } public func UserInfo_BlockActionTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[340]!, self._r[340]!, [_0]) + return formatWithArgumentRanges(self._s[341]!, self._r[341]!, [_0]) } - public var AuthSessions_LogOutApplications: String { return self._s[341]! } - public var ApplyLanguage_ApplySuccess: String { return self._s[342]! } - public var Tour_Title6: String { return self._s[343]! } - public var Map_ChooseAPlace: String { return self._s[344]! } - public var CallSettings_Never: String { return self._s[346]! } + public var AuthSessions_LogOutApplications: String { return self._s[342]! } + public var ApplyLanguage_ApplySuccess: String { return self._s[343]! } + public var Tour_Title6: String { return self._s[344]! } + public var Map_ChooseAPlace: String { return self._s[345]! } + public var CallSettings_Never: String { return self._s[347]! } public func Notification_ChangedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[347]!, self._r[347]!, [_0]) + return formatWithArgumentRanges(self._s[348]!, self._r[348]!, [_0]) } - public var ChannelRemoved_RemoveInfo: String { return self._s[348]! } + public var ChannelRemoved_RemoveInfo: String { return self._s[349]! } public func AutoDownloadSettings_PreloadVideoInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[349]!, self._r[349]!, [_0]) + return formatWithArgumentRanges(self._s[350]!, self._r[350]!, [_0]) } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[350]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsExceptions: String { return self._s[351]! } public func Conversation_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[351]!, self._r[351]!, [_0]) + return formatWithArgumentRanges(self._s[352]!, self._r[352]!, [_0]) } - public var GroupInfo_InviteLink_Title: String { return self._s[352]! } + public var GroupInfo_InviteLink_Title: String { return self._s[353]! } public func Channel_AdminLog_MessageUnkickedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[353]!, self._r[353]!, [_1, _2]) + return formatWithArgumentRanges(self._s[354]!, self._r[354]!, [_1, _2]) } - public var KeyCommand_ScrollUp: String { return self._s[354]! } - public var ContactInfo_URLLabelHomepage: String { return self._s[355]! } - public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[356]! } + public var KeyCommand_ScrollUp: String { return self._s[355]! } + public var ContactInfo_URLLabelHomepage: String { return self._s[356]! } + public var Channel_OwnershipTransfer_ChangeOwner: String { return self._s[357]! } public func Channel_AdminLog_DisabledSlowmode(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[357]!, self._r[357]!, [_0]) + return formatWithArgumentRanges(self._s[358]!, self._r[358]!, [_0]) } - public var TwoFactorSetup_Done_Title: String { return self._s[358]! } + public var TwoFactorSetup_Done_Title: String { return self._s[359]! } public func Conversation_EncryptedPlaceholderTitleOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[359]!, self._r[359]!, [_0]) + return formatWithArgumentRanges(self._s[360]!, self._r[360]!, [_0]) } - public var CallFeedback_ReasonDistortedSpeech: String { return self._s[360]! } - public var Watch_LastSeen_WithinAWeek: String { return self._s[361]! } - public var ContactList_Context_SendMessage: String { return self._s[363]! } - public var Weekday_Tuesday: String { return self._s[364]! } - public var Wallet_Created_Title: String { return self._s[366]! } - public var ScheduledMessages_Delete: String { return self._s[367]! } - public var UserInfo_StartSecretChat: String { return self._s[368]! } - public var Passport_Identity_FilesTitle: String { return self._s[369]! } - public var Permissions_NotificationsAllow_v0: String { return self._s[370]! } - public var DialogList_DeleteConversationConfirmation: String { return self._s[372]! } - public var ChatList_UndoArchiveRevealedTitle: String { return self._s[373]! } + public var CallFeedback_ReasonDistortedSpeech: String { return self._s[361]! } + public var Watch_LastSeen_WithinAWeek: String { return self._s[362]! } + public var ContactList_Context_SendMessage: String { return self._s[364]! } + public var Weekday_Tuesday: String { return self._s[365]! } + public var Wallet_Created_Title: String { return self._s[367]! } + public var ScheduledMessages_Delete: String { return self._s[368]! } + public var UserInfo_StartSecretChat: String { return self._s[369]! } + public var Passport_Identity_FilesTitle: String { return self._s[370]! } + public var Permissions_NotificationsAllow_v0: String { return self._s[371]! } + public var DialogList_DeleteConversationConfirmation: String { return self._s[373]! } + public var ChatList_UndoArchiveRevealedTitle: String { return self._s[374]! } public func Wallet_Configuration_ApplyErrorTextURLUnreachable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[374]!, self._r[374]!, [_0]) + return formatWithArgumentRanges(self._s[375]!, self._r[375]!, [_0]) } - public var AuthSessions_Sessions: String { return self._s[375]! } + public var AuthSessions_Sessions: String { return self._s[376]! } public func Settings_KeepPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[377]!, self._r[377]!, [_0]) + return formatWithArgumentRanges(self._s[378]!, self._r[378]!, [_0]) } - public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[378]! } - public var Call_StatusWaiting: String { return self._s[379]! } - public var CreateGroup_SoftUserLimitAlert: String { return self._s[380]! } - public var FastTwoStepSetup_HintHelp: String { return self._s[381]! } - public var WallpaperPreview_CustomColorBottomText: String { return self._s[382]! } - public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[383]! } - public var LogoutOptions_AddAccountText: String { return self._s[384]! } - public var PasscodeSettings_6DigitCode: String { return self._s[385]! } - public var Settings_LogoutConfirmationText: String { return self._s[386]! } - public var Passport_Identity_TypePassport: String { return self._s[388]! } - public var Map_Work: String { return self._s[391]! } + public var TwoStepAuth_RecoveryEmailChangeDescription: String { return self._s[379]! } + public var Call_StatusWaiting: String { return self._s[380]! } + public var CreateGroup_SoftUserLimitAlert: String { return self._s[381]! } + public var FastTwoStepSetup_HintHelp: String { return self._s[382]! } + public var WallpaperPreview_CustomColorBottomText: String { return self._s[383]! } + public var EditTheme_Expand_Preview_OutgoingText: String { return self._s[384]! } + public var LogoutOptions_AddAccountText: String { return self._s[385]! } + public var PasscodeSettings_6DigitCode: String { return self._s[386]! } + public var Settings_LogoutConfirmationText: String { return self._s[387]! } + public var Passport_Identity_TypePassport: String { return self._s[389]! } + public var Map_Work: String { return self._s[392]! } public func PUSH_MESSAGE_VIDEOS(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[392]!, self._r[392]!, [_1, _2]) + return formatWithArgumentRanges(self._s[393]!, self._r[393]!, [_1, _2]) } - public var SocksProxySetup_SaveProxy: String { return self._s[393]! } - public var AccessDenied_SaveMedia: String { return self._s[394]! } - public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[396]! } - public var CreatePoll_MultipleChoice: String { return self._s[397]! } - public var Settings_Title: String { return self._s[399]! } - public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[400]! } - public var Contacts_InviteSearchLabel: String { return self._s[402]! } - public var PrivacySettings_WebSessions: String { return self._s[403]! } - public var ConvertToSupergroup_Title: String { return self._s[404]! } + public var SocksProxySetup_SaveProxy: String { return self._s[394]! } + public var AccessDenied_SaveMedia: String { return self._s[395]! } + public var Checkout_ErrorInvoiceAlreadyPaid: String { return self._s[397]! } + public var CreatePoll_MultipleChoice: String { return self._s[398]! } + public var Settings_Title: String { return self._s[400]! } + public var VoiceOver_Chat_RecordModeVideoMessageInfo: String { return self._s[401]! } + public var Contacts_InviteSearchLabel: String { return self._s[403]! } + public var PrivacySettings_WebSessions: String { return self._s[404]! } + public var ConvertToSupergroup_Title: String { return self._s[405]! } public func Channel_AdminLog_CaptionEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[405]!, self._r[405]!, [_0]) + return formatWithArgumentRanges(self._s[406]!, self._r[406]!, [_0]) } - public var TwoFactorSetup_Hint_Text: String { return self._s[406]! } - public var InfoPlist_NSSiriUsageDescription: String { return self._s[407]! } + public var TwoFactorSetup_Hint_Text: String { return self._s[407]! } + public var InfoPlist_NSSiriUsageDescription: String { return self._s[408]! } public func PUSH_MESSAGE_CHANNEL_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[408]!, self._r[408]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[409]!, self._r[409]!, [_1, _2, _3]) } - public var ChatSettings_AutomaticPhotoDownload: String { return self._s[409]! } - public var UserInfo_BotHelp: String { return self._s[410]! } - public var PrivacySettings_LastSeenEverybody: String { return self._s[411]! } - public var Checkout_Name: String { return self._s[412]! } - public var AutoDownloadSettings_DataUsage: String { return self._s[413]! } - public var Channel_BanUser_BlockFor: String { return self._s[414]! } - public var Checkout_ShippingAddress: String { return self._s[415]! } - public var AutoDownloadSettings_MaxVideoSize: String { return self._s[416]! } - public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[417]! } - public var Privacy_Forwards: String { return self._s[418]! } - public var Channel_BanUser_PermissionSendPolls: String { return self._s[419]! } - public var Appearance_ThemeCarouselNewNight: String { return self._s[420]! } + public var ChatSettings_AutomaticPhotoDownload: String { return self._s[410]! } + public var UserInfo_BotHelp: String { return self._s[411]! } + public var PrivacySettings_LastSeenEverybody: String { return self._s[412]! } + public var Checkout_Name: String { return self._s[413]! } + public var AutoDownloadSettings_DataUsage: String { return self._s[414]! } + public var Channel_BanUser_BlockFor: String { return self._s[415]! } + public var Checkout_ShippingAddress: String { return self._s[416]! } + public var AutoDownloadSettings_MaxVideoSize: String { return self._s[417]! } + public var Privacy_PaymentsClearInfoDoneHelp: String { return self._s[418]! } + public var Privacy_Forwards: String { return self._s[419]! } + public var Channel_BanUser_PermissionSendPolls: String { return self._s[420]! } + public var Appearance_ThemeCarouselNewNight: String { return self._s[421]! } public func SecretVideo_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[423]!, self._r[423]!, [_0]) + return formatWithArgumentRanges(self._s[424]!, self._r[424]!, [_0]) } - public var Contacts_SortedByName: String { return self._s[424]! } - public var Group_OwnershipTransfer_Title: String { return self._s[425]! } - public var VoiceOver_Chat_OpenHint: String { return self._s[427]! } - public var Group_LeaveGroup: String { return self._s[428]! } - public var Settings_UsernameEmpty: String { return self._s[429]! } + public var Contacts_SortedByName: String { return self._s[425]! } + public var Group_OwnershipTransfer_Title: String { return self._s[426]! } + public var VoiceOver_Chat_OpenHint: String { return self._s[428]! } + public var Group_LeaveGroup: String { return self._s[429]! } + public var Settings_UsernameEmpty: String { return self._s[430]! } public func Notification_PinnedPollMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[430]!, self._r[430]!, [_0]) + return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_0]) } public func TwoStepAuth_ConfirmEmailDescription(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[431]!, self._r[431]!, [_1]) + return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_1]) } public func Channel_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[432]!, self._r[432]!, [_1, _2]) + return formatWithArgumentRanges(self._s[433]!, self._r[433]!, [_1, _2]) } - public var Message_ImageExpired: String { return self._s[433]! } - public var TwoStepAuth_RecoveryFailed: String { return self._s[435]! } - public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[436]! } - public var UserInfo_AddToExisting: String { return self._s[437]! } - public var TwoStepAuth_EnabledSuccess: String { return self._s[438]! } - public var Wallet_Send_SyncInProgress: String { return self._s[439]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[440]! } + public var Message_ImageExpired: String { return self._s[434]! } + public var TwoStepAuth_RecoveryFailed: String { return self._s[436]! } + public var EditTheme_Edit_Preview_OutgoingText: String { return self._s[437]! } + public var UserInfo_AddToExisting: String { return self._s[438]! } + public var TwoStepAuth_EnabledSuccess: String { return self._s[439]! } + public var Wallet_Send_SyncInProgress: String { return self._s[440]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_SetColor: String { return self._s[441]! } public func PUSH_CHANNEL_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[441]!, self._r[441]!, [_1]) + return formatWithArgumentRanges(self._s[442]!, self._r[442]!, [_1]) } - public var Notifications_GroupNotificationsAlert: String { return self._s[442]! } - public var Passport_Language_km: String { return self._s[443]! } - public var SocksProxySetup_AdNoticeHelp: String { return self._s[445]! } - public var VoiceOver_Media_PlaybackPlay: String { return self._s[446]! } - public var Notification_CallMissedShort: String { return self._s[447]! } - public var Wallet_Info_YourBalance: String { return self._s[448]! } - public var ReportPeer_ReasonOther_Send: String { return self._s[449]! } - public var Watch_Compose_Send: String { return self._s[450]! } - public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[453]! } - public var TwoFactorSetup_Email_Action: String { return self._s[454]! } - public var Conversation_HoldForVideo: String { return self._s[455]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[456]! } - public var AuthSessions_OtherDevices: String { return self._s[457]! } - public var Wallet_TransactionInfo_CommentHeader: String { return self._s[458]! } - public var CheckoutInfo_ErrorCityInvalid: String { return self._s[460]! } - public var Appearance_AutoNightThemeDisabled: String { return self._s[462]! } - public var Channel_LinkItem: String { return self._s[463]! } + public var Notifications_GroupNotificationsAlert: String { return self._s[443]! } + public var Passport_Language_km: String { return self._s[444]! } + public var SocksProxySetup_AdNoticeHelp: String { return self._s[446]! } + public var VoiceOver_Media_PlaybackPlay: String { return self._s[447]! } + public var Notification_CallMissedShort: String { return self._s[448]! } + public var Wallet_Info_YourBalance: String { return self._s[449]! } + public var ReportPeer_ReasonOther_Send: String { return self._s[451]! } + public var Watch_Compose_Send: String { return self._s[452]! } + public var Passport_Identity_TypeInternalPassportUploadScan: String { return self._s[455]! } + public var TwoFactorSetup_Email_Action: String { return self._s[456]! } + public var Conversation_HoldForVideo: String { return self._s[457]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalidData: String { return self._s[458]! } + public var AuthSessions_OtherDevices: String { return self._s[459]! } + public var Wallet_TransactionInfo_CommentHeader: String { return self._s[460]! } + public var CheckoutInfo_ErrorCityInvalid: String { return self._s[462]! } + public var Appearance_AutoNightThemeDisabled: String { return self._s[464]! } + public var Channel_LinkItem: String { return self._s[465]! } public func PrivacySettings_LastSeenContactsMinusPlus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[464]!, self._r[464]!, [_0, _1]) + return formatWithArgumentRanges(self._s[466]!, self._r[466]!, [_0, _1]) } public func Passport_Identity_NativeNameTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[467]!, self._r[467]!, [_0]) + return formatWithArgumentRanges(self._s[469]!, self._r[469]!, [_0]) } - public var VoiceOver_Recording_StopAndPreview: String { return self._s[468]! } - public var Passport_Language_dv: String { return self._s[469]! } - public var Undo_LeftChannel: String { return self._s[470]! } - public var Notifications_ExceptionsMuted: String { return self._s[471]! } - public var ChatList_UnhideAction: String { return self._s[472]! } - public var Conversation_ContextMenuShare: String { return self._s[473]! } - public var Conversation_ContextMenuStickerPackInfo: String { return self._s[474]! } - public var ShareFileTip_Title: String { return self._s[475]! } - public var NotificationsSound_Chord: String { return self._s[476]! } - public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[477]! } + public var VoiceOver_Recording_StopAndPreview: String { return self._s[470]! } + public var Passport_Language_dv: String { return self._s[471]! } + public var Undo_LeftChannel: String { return self._s[472]! } + public var Notifications_ExceptionsMuted: String { return self._s[473]! } + public var ChatList_UnhideAction: String { return self._s[474]! } + public var Conversation_ContextMenuShare: String { return self._s[475]! } + public var Conversation_ContextMenuStickerPackInfo: String { return self._s[476]! } + public var ShareFileTip_Title: String { return self._s[477]! } + public var NotificationsSound_Chord: String { return self._s[478]! } + public var Wallet_TransactionInfo_OtherFeeHeader: String { return self._s[479]! } public func PUSH_CHAT_RETURNED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[478]!, self._r[478]!, [_1, _2]) + return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_1, _2]) } - public var Passport_Address_EditTemporaryRegistration: String { return self._s[479]! } + public var Passport_Address_EditTemporaryRegistration: String { return self._s[481]! } public func Notification_Joined(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[480]!, self._r[480]!, [_0]) + return formatWithArgumentRanges(self._s[482]!, self._r[482]!, [_0]) } public func Wallet_Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[481]!, self._r[481]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[483]!, self._r[483]!, [_1, _2, _3]) } - public var Wallet_Settings_ConfigurationInfo: String { return self._s[482]! } - public var Wallpaper_ErrorNotFound: String { return self._s[483]! } - public var Notification_CallOutgoingShort: String { return self._s[485]! } - public var Wallet_WordImport_IncorrectText: String { return self._s[486]! } + public var Wallet_Settings_ConfigurationInfo: String { return self._s[484]! } + public var Wallpaper_ErrorNotFound: String { return self._s[485]! } + public var Notification_CallOutgoingShort: String { return self._s[487]! } + public var Wallet_WordImport_IncorrectText: String { return self._s[488]! } public func Watch_Time_ShortFullAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[487]!, self._r[487]!, [_1, _2]) + return formatWithArgumentRanges(self._s[489]!, self._r[489]!, [_1, _2]) } - public var Passport_Address_TypeUtilityBill: String { return self._s[488]! } - public var Privacy_Forwards_LinkIfAllowed: String { return self._s[489]! } - public var ReportPeer_Report: String { return self._s[490]! } - public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[491]! } - public var GroupInfo_DeactivatedStatus: String { return self._s[492]! } + public var Passport_Address_TypeUtilityBill: String { return self._s[490]! } + public var Privacy_Forwards_LinkIfAllowed: String { return self._s[491]! } + public var ReportPeer_Report: String { return self._s[492]! } + public var SettingsSearch_Synonyms_Proxy_Title: String { return self._s[493]! } + public var GroupInfo_DeactivatedStatus: String { return self._s[494]! } public func VoiceOver_Chat_MusicTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[493]!, self._r[493]!, [_1, _2]) + return formatWithArgumentRanges(self._s[495]!, self._r[495]!, [_1, _2]) } - public var StickerPack_Send: String { return self._s[494]! } - public var Login_CodeSentInternal: String { return self._s[495]! } - public var Wallet_Month_GenJanuary: String { return self._s[496]! } - public var GroupInfo_InviteLink_LinkSection: String { return self._s[497]! } + public var StickerPack_Send: String { return self._s[496]! } + public var Login_CodeSentInternal: String { return self._s[497]! } + public var Wallet_Month_GenJanuary: String { return self._s[498]! } + public var GroupInfo_InviteLink_LinkSection: String { return self._s[499]! } public func Channel_AdminLog_MessageDeleted(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[498]!, self._r[498]!, [_0]) - } - public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[500]!, self._r[500]!, [_0]) } - public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[501]! } - public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_1]) + public func Conversation_EncryptionWaiting(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[502]!, self._r[502]!, [_0]) } - public var ReportPeer_ReasonViolence: String { return self._s[504]! } - public var Appearance_ShareThemeColor: String { return self._s[505]! } - public var Map_Locating: String { return self._s[506]! } + public var Channel_BanUser_PermissionSendStickersAndGifs: String { return self._s[503]! } + public func PUSH_PINNED_GAME(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[504]!, self._r[504]!, [_1]) + } + public var ReportPeer_ReasonViolence: String { return self._s[506]! } + public var Appearance_ShareThemeColor: String { return self._s[507]! } + public var Map_Locating: String { return self._s[508]! } public func VoiceOver_Chat_VideoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[507]!, self._r[507]!, [_0]) + return formatWithArgumentRanges(self._s[509]!, self._r[509]!, [_0]) } public func PUSH_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[508]!, self._r[508]!, [_1]) + return formatWithArgumentRanges(self._s[510]!, self._r[510]!, [_1]) } - public var AutoDownloadSettings_GroupChats: String { return self._s[510]! } - public var CheckoutInfo_SaveInfo: String { return self._s[511]! } - public var SharedMedia_EmptyLinksText: String { return self._s[513]! } - public var Passport_Address_CityPlaceholder: String { return self._s[514]! } - public var CheckoutInfo_ErrorStateInvalid: String { return self._s[515]! } - public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[516]! } - public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[518]! } - public var Channel_AdminLog_CanAddAdmins: String { return self._s[519]! } + public var AutoDownloadSettings_GroupChats: String { return self._s[512]! } + public var CheckoutInfo_SaveInfo: String { return self._s[513]! } + public var SharedMedia_EmptyLinksText: String { return self._s[515]! } + public var Passport_Address_CityPlaceholder: String { return self._s[516]! } + public var CheckoutInfo_ErrorStateInvalid: String { return self._s[517]! } + public var Privacy_ProfilePhoto_CustomHelp: String { return self._s[518]! } + public var Wallet_Send_OwnAddressAlertTitle: String { return self._s[520]! } + public var Channel_AdminLog_CanAddAdmins: String { return self._s[521]! } public func PUSH_CHANNEL_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[520]!, self._r[520]!, [_1]) + return formatWithArgumentRanges(self._s[522]!, self._r[522]!, [_1]) } public func Time_MonthOfYear_m8(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[521]!, self._r[521]!, [_0]) + return formatWithArgumentRanges(self._s[523]!, self._r[523]!, [_0]) } - public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[522]! } - public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[523]! } - public var ChangePhoneNumberCode_Code: String { return self._s[524]! } - public var Appearance_CreateTheme: String { return self._s[525]! } + public var InfoPlist_NSLocationWhenInUseUsageDescription: String { return self._s[524]! } + public var GroupInfo_InviteLink_RevokeAlert_Success: String { return self._s[525]! } + public var ChangePhoneNumberCode_Code: String { return self._s[526]! } + public var Appearance_CreateTheme: String { return self._s[527]! } public func UserInfo_NotificationsDefaultSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[526]!, self._r[526]!, [_0]) + return formatWithArgumentRanges(self._s[528]!, self._r[528]!, [_0]) } - public var TwoStepAuth_SetupEmail: String { return self._s[527]! } - public var HashtagSearch_AllChats: String { return self._s[528]! } - public var MediaPlayer_UnknownTrack: String { return self._s[529]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[531]! } + public var TwoStepAuth_SetupEmail: String { return self._s[529]! } + public var HashtagSearch_AllChats: String { return self._s[530]! } + public var MediaPlayer_UnknownTrack: String { return self._s[531]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular: String { return self._s[533]! } public func ChatList_DeleteForEveryone(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[532]!, self._r[532]!, [_0]) + return formatWithArgumentRanges(self._s[534]!, self._r[534]!, [_0]) } - public var PhotoEditor_QualityHigh: String { return self._s[534]! } + public var PhotoEditor_QualityHigh: String { return self._s[536]! } public func Passport_Phone_UseTelegramNumber(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[535]!, self._r[535]!, [_0]) + return formatWithArgumentRanges(self._s[537]!, self._r[537]!, [_0]) } - public var ApplyLanguage_ApplyLanguageAction: String { return self._s[536]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[537]! } - public var Message_LiveLocation: String { return self._s[538]! } - public var Cache_LowDiskSpaceText: String { return self._s[539]! } - public var Wallet_Receive_ShareAddress: String { return self._s[540]! } - public var EditTheme_ErrorLinkTaken: String { return self._s[541]! } - public var Conversation_SendMessage: String { return self._s[542]! } - public var AuthSessions_EmptyTitle: String { return self._s[543]! } - public var Privacy_PhoneNumber: String { return self._s[544]! } - public var PeopleNearby_CreateGroup: String { return self._s[545]! } - public var CallSettings_UseLessData: String { return self._s[546]! } - public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[547]! } - public var Stickers_AddToFavorites: String { return self._s[548]! } - public var Wallet_WordImport_Title: String { return self._s[549]! } - public var PhotoEditor_QualityLow: String { return self._s[550]! } - public var Watch_UserInfo_Unblock: String { return self._s[551]! } - public var Settings_Logout: String { return self._s[552]! } + public var ApplyLanguage_ApplyLanguageAction: String { return self._s[538]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsPreview: String { return self._s[539]! } + public var Message_LiveLocation: String { return self._s[540]! } + public var Cache_LowDiskSpaceText: String { return self._s[541]! } + public var Wallet_Receive_ShareAddress: String { return self._s[542]! } + public var EditTheme_ErrorLinkTaken: String { return self._s[543]! } + public var Conversation_SendMessage: String { return self._s[544]! } + public var AuthSessions_EmptyTitle: String { return self._s[545]! } + public var Privacy_PhoneNumber: String { return self._s[546]! } + public var PeopleNearby_CreateGroup: String { return self._s[547]! } + public var CallSettings_UseLessData: String { return self._s[549]! } + public var NetworkUsageSettings_MediaDocumentDataSection: String { return self._s[550]! } + public var Stickers_AddToFavorites: String { return self._s[551]! } + public var Wallet_WordImport_Title: String { return self._s[552]! } + public var PhotoEditor_QualityLow: String { return self._s[553]! } + public var Watch_UserInfo_Unblock: String { return self._s[554]! } + public var Settings_Logout: String { return self._s[555]! } public func PUSH_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[553]!, self._r[553]!, [_1]) + return formatWithArgumentRanges(self._s[556]!, self._r[556]!, [_1]) } - public var ContactInfo_PhoneLabelWork: String { return self._s[554]! } - public var ChannelInfo_Stats: String { return self._s[555]! } - public var TextFormat_Link: String { return self._s[556]! } + public var ContactInfo_PhoneLabelWork: String { return self._s[557]! } + public var ChannelInfo_Stats: String { return self._s[558]! } + public var TextFormat_Link: String { return self._s[559]! } public func Date_ChatDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[557]!, self._r[557]!, [_1, _2]) + return formatWithArgumentRanges(self._s[560]!, self._r[560]!, [_1, _2]) } - public var Wallet_TransactionInfo_Title: String { return self._s[558]! } + public var Wallet_TransactionInfo_Title: String { return self._s[561]! } public func Message_ForwardedMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[559]!, self._r[559]!, [_0]) + return formatWithArgumentRanges(self._s[562]!, self._r[562]!, [_0]) } - public var Watch_Notification_Joined: String { return self._s[560]! } - public var Group_Setup_TypePublicHelp: String { return self._s[561]! } - public var Passport_Scans_UploadNew: String { return self._s[562]! } - public var Checkout_LiabilityAlertTitle: String { return self._s[563]! } - public var DialogList_Title: String { return self._s[566]! } - public var NotificationSettings_ContactJoined: String { return self._s[567]! } - public var GroupInfo_LabelAdmin: String { return self._s[568]! } - public var KeyCommand_ChatInfo: String { return self._s[569]! } - public var Conversation_EditingCaptionPanelTitle: String { return self._s[570]! } - public var Call_ReportIncludeLog: String { return self._s[571]! } + public var Watch_Notification_Joined: String { return self._s[563]! } + public var Group_Setup_TypePublicHelp: String { return self._s[564]! } + public var Passport_Scans_UploadNew: String { return self._s[565]! } + public var Checkout_LiabilityAlertTitle: String { return self._s[566]! } + public var DialogList_Title: String { return self._s[569]! } + public var NotificationSettings_ContactJoined: String { return self._s[570]! } + public var GroupInfo_LabelAdmin: String { return self._s[571]! } + public var KeyCommand_ChatInfo: String { return self._s[572]! } + public var Conversation_EditingCaptionPanelTitle: String { return self._s[573]! } + public var Call_ReportIncludeLog: String { return self._s[574]! } public func Notifications_ExceptionsChangeSound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[574]!, self._r[574]!, [_0]) + return formatWithArgumentRanges(self._s[577]!, self._r[577]!, [_0]) } - public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[575]! } - public var ChatAdmins_AllMembersAreAdmins: String { return self._s[576]! } - public var LocalGroup_IrrelevantWarning: String { return self._s[577]! } - public var Conversation_DefaultRestrictedInline: String { return self._s[578]! } - public var Message_Sticker: String { return self._s[579]! } - public var LastSeen_JustNow: String { return self._s[581]! } - public var Passport_Email_EmailPlaceholder: String { return self._s[583]! } - public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[584]! } - public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[585]! } - public var Channel_EditAdmin_PermissionsHeader: String { return self._s[586]! } - public var TwoStepAuth_Email: String { return self._s[587]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[588]! } - public var PhotoEditor_BlurToolOff: String { return self._s[589]! } - public var Message_PinnedStickerMessage: String { return self._s[590]! } - public var ContactInfo_PhoneLabelPager: String { return self._s[591]! } - public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[592]! } - public var Passport_DiscardMessageTitle: String { return self._s[593]! } - public var Privacy_PaymentsTitle: String { return self._s[594]! } - public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[595]! } - public var ClearCache_StorageCache: String { return self._s[596]! } - public var Appearance_TextSizeSetting: String { return self._s[597]! } - public var Channel_DiscussionGroup_Header: String { return self._s[599]! } - public var VoiceOver_Chat_OptionSelected: String { return self._s[600]! } - public var Appearance_ColorTheme: String { return self._s[601]! } - public var UserInfo_ShareContact: String { return self._s[602]! } - public var Passport_Address_TypePassportRegistration: String { return self._s[603]! } - public var Common_More: String { return self._s[604]! } - public var Watch_Message_Call: String { return self._s[605]! } - public var Profile_EncryptionKey: String { return self._s[608]! } - public var Privacy_TopPeers: String { return self._s[609]! } - public var Conversation_StopPollConfirmation: String { return self._s[610]! } - public var Wallet_Words_NotDoneText: String { return self._s[612]! } - public var Privacy_TopPeersWarning: String { return self._s[614]! } - public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[615]! } - public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[616]! } - public var Wallet_RestoreFailed_EnterWords: String { return self._s[619]! } - public var DialogList_SearchSectionMessages: String { return self._s[620]! } - public var Notifications_ChannelNotifications: String { return self._s[621]! } - public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[622]! } - public var Passport_Language_sk: String { return self._s[623]! } - public var Notification_MessageLifetime1h: String { return self._s[624]! } - public var Wallpaper_ResetWallpapersInfo: String { return self._s[625]! } - public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[626]! } - public var Call_ReportSkip: String { return self._s[628]! } - public var Cache_ServiceFiles: String { return self._s[629]! } - public var Group_ErrorAddTooMuchAdmins: String { return self._s[630]! } - public var VoiceOver_Chat_YourFile: String { return self._s[631]! } - public var Map_Hybrid: String { return self._s[632]! } - public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[634]! } - public var ChatSettings_AutoDownloadVideos: String { return self._s[636]! } - public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[637]! } - public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[638]! } - public var SocksProxySetup_ProxyTelegram: String { return self._s[641]! } + public var Channel_AdminLog_InfoPanelChannelAlertText: String { return self._s[578]! } + public var ChatAdmins_AllMembersAreAdmins: String { return self._s[579]! } + public var LocalGroup_IrrelevantWarning: String { return self._s[580]! } + public var Conversation_DefaultRestrictedInline: String { return self._s[581]! } + public var Message_Sticker: String { return self._s[582]! } + public var LastSeen_JustNow: String { return self._s[584]! } + public var Passport_Email_EmailPlaceholder: String { return self._s[586]! } + public var SettingsSearch_Synonyms_AppLanguage: String { return self._s[587]! } + public var Channel_AdminLogFilter_EventsEditedMessages: String { return self._s[588]! } + public var Channel_EditAdmin_PermissionsHeader: String { return self._s[589]! } + public var TwoStepAuth_Email: String { return self._s[590]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsSound: String { return self._s[591]! } + public var PhotoEditor_BlurToolOff: String { return self._s[592]! } + public var Message_PinnedStickerMessage: String { return self._s[593]! } + public var ContactInfo_PhoneLabelPager: String { return self._s[594]! } + public var SettingsSearch_Synonyms_Appearance_TextSize: String { return self._s[595]! } + public var Passport_DiscardMessageTitle: String { return self._s[596]! } + public var Privacy_PaymentsTitle: String { return self._s[597]! } + public var EditTheme_Edit_Preview_IncomingReplyName: String { return self._s[598]! } + public var ClearCache_StorageCache: String { return self._s[599]! } + public var Appearance_TextSizeSetting: String { return self._s[600]! } + public var Channel_DiscussionGroup_Header: String { return self._s[602]! } + public var VoiceOver_Chat_OptionSelected: String { return self._s[603]! } + public var Appearance_ColorTheme: String { return self._s[604]! } + public var UserInfo_ShareContact: String { return self._s[605]! } + public var Passport_Address_TypePassportRegistration: String { return self._s[606]! } + public var Common_More: String { return self._s[607]! } + public var Watch_Message_Call: String { return self._s[608]! } + public var Profile_EncryptionKey: String { return self._s[611]! } + public var Privacy_TopPeers: String { return self._s[612]! } + public var Conversation_StopPollConfirmation: String { return self._s[613]! } + public var Wallet_Words_NotDoneText: String { return self._s[615]! } + public var Privacy_TopPeersWarning: String { return self._s[617]! } + public var SettingsSearch_Synonyms_Data_DownloadInBackground: String { return self._s[618]! } + public var SettingsSearch_Synonyms_Data_Storage_KeepMedia: String { return self._s[619]! } + public var Wallet_RestoreFailed_EnterWords: String { return self._s[622]! } + public var DialogList_SearchSectionMessages: String { return self._s[623]! } + public var Notifications_ChannelNotifications: String { return self._s[624]! } + public var CheckoutInfo_ShippingInfoAddress1Placeholder: String { return self._s[625]! } + public var Passport_Language_sk: String { return self._s[626]! } + public var Notification_MessageLifetime1h: String { return self._s[627]! } + public var Wallpaper_ResetWallpapersInfo: String { return self._s[628]! } + public var Appearance_ThemePreview_Chat_5_Text: String { return self._s[629]! } + public var Call_ReportSkip: String { return self._s[631]! } + public var Cache_ServiceFiles: String { return self._s[632]! } + public var Group_ErrorAddTooMuchAdmins: String { return self._s[633]! } + public var VoiceOver_Chat_YourFile: String { return self._s[634]! } + public var Map_Hybrid: String { return self._s[635]! } + public var Contacts_SearchUsersAndGroupsLabel: String { return self._s[637]! } + public var ChatSettings_AutoDownloadVideos: String { return self._s[639]! } + public var Channel_BanUser_PermissionEmbedLinks: String { return self._s[640]! } + public var InfoPlist_NSLocationAlwaysAndWhenInUseUsageDescription: String { return self._s[641]! } + public var SocksProxySetup_ProxyTelegram: String { return self._s[644]! } public func PUSH_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[642]!, self._r[642]!, [_1]) + return formatWithArgumentRanges(self._s[645]!, self._r[645]!, [_1]) } - public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[644]! } - public var ScheduledMessages_ScheduledToday: String { return self._s[645]! } + public var Channel_Username_CreatePrivateLinkHelp: String { return self._s[647]! } + public var ScheduledMessages_ScheduledToday: String { return self._s[648]! } public func PUSH_CHAT_TITLE_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[646]!, self._r[646]!, [_1, _2]) + return formatWithArgumentRanges(self._s[649]!, self._r[649]!, [_1, _2]) } - public var Conversation_LiveLocationYou: String { return self._s[647]! } - public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[648]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[649]! } - public var UserInfo_ShareBot: String { return self._s[652]! } + public var Conversation_LiveLocationYou: String { return self._s[650]! } + public var SettingsSearch_Synonyms_Privacy_Calls: String { return self._s[651]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsPreview: String { return self._s[652]! } + public var UserInfo_ShareBot: String { return self._s[655]! } public func PUSH_AUTH_REGION(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[653]!, self._r[653]!, [_1, _2]) + return formatWithArgumentRanges(self._s[656]!, self._r[656]!, [_1, _2]) } - public var Conversation_ClearCache: String { return self._s[654]! } - public var PhotoEditor_ShadowsTint: String { return self._s[655]! } - public var Message_Audio: String { return self._s[656]! } - public var Passport_Language_lt: String { return self._s[657]! } + public var Conversation_ClearCache: String { return self._s[657]! } + public var PhotoEditor_ShadowsTint: String { return self._s[658]! } + public var Message_Audio: String { return self._s[659]! } + public var Passport_Language_lt: String { return self._s[660]! } public func Message_PinnedTextMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[658]!, self._r[658]!, [_0]) + return formatWithArgumentRanges(self._s[661]!, self._r[661]!, [_0]) } - public var Permissions_SiriText_v0: String { return self._s[659]! } - public var Conversation_FileICloudDrive: String { return self._s[660]! } - public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[661]! } - public var Notifications_Badge_IncludeMutedChats: String { return self._s[662]! } + public var Permissions_SiriText_v0: String { return self._s[662]! } + public var Conversation_FileICloudDrive: String { return self._s[663]! } + public var ChatList_DeleteForEveryoneConfirmationTitle: String { return self._s[664]! } + public var Notifications_Badge_IncludeMutedChats: String { return self._s[665]! } public func Notification_NewAuthDetected(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[663]!, self._r[663]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[666]!, self._r[666]!, [_1, _2, _3, _4, _5, _6]) } - public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[664]! } + public var DialogList_ProxyConnectionIssuesTooltip: String { return self._s[667]! } public func Time_MonthOfYear_m5(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[665]!, self._r[665]!, [_0]) + return formatWithArgumentRanges(self._s[668]!, self._r[668]!, [_0]) } - public var Channel_SignMessages: String { return self._s[666]! } + public var Channel_SignMessages: String { return self._s[669]! } public func PUSH_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[667]!, self._r[667]!, [_1]) + return formatWithArgumentRanges(self._s[670]!, self._r[670]!, [_1]) } - public var Compose_ChannelTokenListPlaceholder: String { return self._s[668]! } - public var Passport_ScanPassport: String { return self._s[669]! } - public var Watch_Suggestion_Thanks: String { return self._s[670]! } - public var BlockedUsers_AddNew: String { return self._s[671]! } + public var Compose_ChannelTokenListPlaceholder: String { return self._s[671]! } + public var Passport_ScanPassport: String { return self._s[672]! } + public var Watch_Suggestion_Thanks: String { return self._s[673]! } + public var BlockedUsers_AddNew: String { return self._s[674]! } public func PUSH_CHAT_MESSAGE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[672]!, self._r[672]!, [_1, _2]) + return formatWithArgumentRanges(self._s[675]!, self._r[675]!, [_1, _2]) } - public var Watch_Message_Invoice: String { return self._s[673]! } - public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[674]! } - public var Month_GenJuly: String { return self._s[675]! } - public var CreatePoll_QuizInfo: String { return self._s[676]! } - public var UserInfo_StartSecretChatStart: String { return self._s[677]! } - public var SocksProxySetup_ProxySocks5: String { return self._s[678]! } - public var IntentsSettings_SuggestByShare: String { return self._s[680]! } - public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[681]! } - public var Notification_ChannelInviterSelf: String { return self._s[682]! } - public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[683]! } + public var Watch_Message_Invoice: String { return self._s[676]! } + public var SettingsSearch_Synonyms_Privacy_LastSeen: String { return self._s[677]! } + public var Month_GenJuly: String { return self._s[678]! } + public var CreatePoll_QuizInfo: String { return self._s[679]! } + public var UserInfo_StartSecretChatStart: String { return self._s[680]! } + public var SocksProxySetup_ProxySocks5: String { return self._s[681]! } + public var IntentsSettings_SuggestByShare: String { return self._s[683]! } + public var Notification_Exceptions_DeleteAllConfirmation: String { return self._s[684]! } + public var Notification_ChannelInviterSelf: String { return self._s[685]! } + public var CheckoutInfo_ReceiverInfoEmail: String { return self._s[686]! } public func ApplyLanguage_ChangeLanguageUnofficialText(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[684]!, self._r[684]!, [_1, _2]) + return formatWithArgumentRanges(self._s[687]!, self._r[687]!, [_1, _2]) } - public var CheckoutInfo_Title: String { return self._s[685]! } - public var Watch_Stickers_RecentPlaceholder: String { return self._s[686]! } + public var CheckoutInfo_Title: String { return self._s[688]! } + public var Watch_Stickers_RecentPlaceholder: String { return self._s[689]! } public func Map_DistanceAway(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[687]!, self._r[687]!, [_0]) + return formatWithArgumentRanges(self._s[690]!, self._r[690]!, [_0]) } - public var Passport_Identity_MainPage: String { return self._s[688]! } - public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[689]! } - public var Passport_Language_de: String { return self._s[690]! } - public var Update_Title: String { return self._s[691]! } - public var ContactInfo_PhoneLabelWorkFax: String { return self._s[692]! } - public var Channel_AdminLog_BanEmbedLinks: String { return self._s[693]! } - public var Passport_Email_UseTelegramEmailHelp: String { return self._s[694]! } - public var Notifications_ChannelNotificationsPreview: String { return self._s[695]! } - public var NotificationsSound_Telegraph: String { return self._s[696]! } - public var Watch_LastSeen_ALongTimeAgo: String { return self._s[697]! } - public var ChannelMembers_WhoCanAddMembers: String { return self._s[698]! } + public var Passport_Identity_MainPage: String { return self._s[691]! } + public var TwoStepAuth_ConfirmEmailResendCode: String { return self._s[692]! } + public var Passport_Language_de: String { return self._s[693]! } + public var Update_Title: String { return self._s[694]! } + public var ContactInfo_PhoneLabelWorkFax: String { return self._s[695]! } + public var Channel_AdminLog_BanEmbedLinks: String { return self._s[696]! } + public var Passport_Email_UseTelegramEmailHelp: String { return self._s[697]! } + public var Notifications_ChannelNotificationsPreview: String { return self._s[698]! } + public var NotificationsSound_Telegraph: String { return self._s[699]! } + public var Watch_LastSeen_ALongTimeAgo: String { return self._s[700]! } + public var ChannelMembers_WhoCanAddMembers: String { return self._s[701]! } public func AutoDownloadSettings_UpTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[699]!, self._r[699]!, [_0]) + return formatWithArgumentRanges(self._s[702]!, self._r[702]!, [_0]) } - public var ClearCache_Description: String { return self._s[700]! } - public var Stickers_SuggestAll: String { return self._s[701]! } - public var Conversation_ForwardTitle: String { return self._s[702]! } - public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[703]! } + public var ClearCache_Description: String { return self._s[703]! } + public var Stickers_SuggestAll: String { return self._s[704]! } + public var Conversation_ForwardTitle: String { return self._s[705]! } + public var Appearance_ThemePreview_ChatList_7_Name: String { return self._s[706]! } public func Notification_JoinedChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[704]!, self._r[704]!, [_0]) + return formatWithArgumentRanges(self._s[707]!, self._r[707]!, [_0]) } - public var Calls_NewCall: String { return self._s[705]! } - public var Call_StatusEnded: String { return self._s[706]! } - public var AutoDownloadSettings_DataUsageLow: String { return self._s[707]! } - public var Settings_ProxyConnected: String { return self._s[708]! } - public var Channel_AdminLogFilter_EventsPinned: String { return self._s[709]! } - public var PhotoEditor_QualityVeryLow: String { return self._s[710]! } - public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[711]! } - public var Passport_PasswordPlaceholder: String { return self._s[712]! } - public var Message_PinnedInvoice: String { return self._s[713]! } - public var Passport_Identity_IssueDate: String { return self._s[714]! } - public var Passport_Language_pl: String { return self._s[715]! } + public var Calls_NewCall: String { return self._s[708]! } + public var Call_StatusEnded: String { return self._s[709]! } + public var AutoDownloadSettings_DataUsageLow: String { return self._s[710]! } + public var Settings_ProxyConnected: String { return self._s[711]! } + public var Channel_AdminLogFilter_EventsPinned: String { return self._s[712]! } + public var PhotoEditor_QualityVeryLow: String { return self._s[713]! } + public var Channel_AdminLogFilter_EventsDeletedMessages: String { return self._s[714]! } + public var Passport_PasswordPlaceholder: String { return self._s[715]! } + public var Message_PinnedInvoice: String { return self._s[716]! } + public var Passport_Identity_IssueDate: String { return self._s[717]! } + public var Passport_Language_pl: String { return self._s[718]! } public func ChannelInfo_ChannelForbidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[716]!, self._r[716]!, [_0]) - } - public var SocksProxySetup_PasteFromClipboard: String { return self._s[717]! } - public var Call_StatusConnecting: String { return self._s[718]! } - public func Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[719]!, self._r[719]!, [_0]) } - public var ChatSettings_ConnectionType_UseProxy: String { return self._s[721]! } - public var Common_Edit: String { return self._s[722]! } - public var PrivacySettings_LastSeenNobody: String { return self._s[723]! } + public var SocksProxySetup_PasteFromClipboard: String { return self._s[720]! } + public var Call_StatusConnecting: String { return self._s[721]! } + public func Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[722]!, self._r[722]!, [_0]) + } + public var ChatSettings_ConnectionType_UseProxy: String { return self._s[724]! } + public var Common_Edit: String { return self._s[725]! } + public var PrivacySettings_LastSeenNobody: String { return self._s[726]! } public func Notification_LeftChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[724]!, self._r[724]!, [_0]) + return formatWithArgumentRanges(self._s[727]!, self._r[727]!, [_0]) } - public var GroupInfo_ChatAdmins: String { return self._s[725]! } - public var PrivateDataSettings_Title: String { return self._s[726]! } - public var Login_CancelPhoneVerificationStop: String { return self._s[727]! } - public var ChatList_Read: String { return self._s[728]! } - public var Wallet_WordImport_Text: String { return self._s[729]! } - public var Undo_ChatClearedForBothSides: String { return self._s[730]! } - public var GroupPermission_SectionTitle: String { return self._s[731]! } - public var TwoFactorSetup_Intro_Title: String { return self._s[733]! } + public var GroupInfo_ChatAdmins: String { return self._s[728]! } + public var PrivateDataSettings_Title: String { return self._s[729]! } + public var Login_CancelPhoneVerificationStop: String { return self._s[730]! } + public var ChatList_Read: String { return self._s[731]! } + public var Wallet_WordImport_Text: String { return self._s[732]! } + public var Undo_ChatClearedForBothSides: String { return self._s[733]! } + public var GroupPermission_SectionTitle: String { return self._s[734]! } + public var TwoFactorSetup_Intro_Title: String { return self._s[736]! } public func PUSH_CHAT_LEFT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[734]!, self._r[734]!, [_1, _2]) + return formatWithArgumentRanges(self._s[737]!, self._r[737]!, [_1, _2]) } - public var Checkout_ErrorPaymentFailed: String { return self._s[735]! } - public var Update_UpdateApp: String { return self._s[736]! } - public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[737]! } - public var Settings_Appearance: String { return self._s[738]! } - public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[742]! } - public var Watch_Location_Access: String { return self._s[743]! } - public var ShareMenu_CopyShareLink: String { return self._s[745]! } - public var TwoStepAuth_SetupHintTitle: String { return self._s[746]! } - public var Conversation_Theme: String { return self._s[748]! } + public var Checkout_ErrorPaymentFailed: String { return self._s[738]! } + public var Update_UpdateApp: String { return self._s[739]! } + public var Group_Username_RevokeExistingUsernamesInfo: String { return self._s[740]! } + public var Settings_Appearance: String { return self._s[741]! } + public var SettingsSearch_Synonyms_Stickers_SuggestStickers: String { return self._s[745]! } + public var Watch_Location_Access: String { return self._s[746]! } + public var ShareMenu_CopyShareLink: String { return self._s[748]! } + public var TwoStepAuth_SetupHintTitle: String { return self._s[749]! } + public var Conversation_Theme: String { return self._s[751]! } public func DialogList_SingleRecordingVideoMessageSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[749]!, self._r[749]!, [_0]) + return formatWithArgumentRanges(self._s[752]!, self._r[752]!, [_0]) } - public var Notifications_ClassicTones: String { return self._s[750]! } - public var Weekday_ShortWednesday: String { return self._s[751]! } - public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[752]! } - public var Undo_LeftGroup: String { return self._s[755]! } - public var Wallet_RestoreFailed_Text: String { return self._s[756]! } - public var Conversation_LinkDialogCopy: String { return self._s[757]! } - public var Wallet_TransactionInfo_NoAddress: String { return self._s[759]! } - public var Wallet_Navigation_Back: String { return self._s[760]! } - public var KeyCommand_FocusOnInputField: String { return self._s[761]! } - public var Contacts_SelectAll: String { return self._s[762]! } - public var Preview_SaveToCameraRoll: String { return self._s[763]! } - public var PrivacySettings_PasscodeOff: String { return self._s[764]! } - public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[765]! } - public var Wallpaper_Title: String { return self._s[766]! } - public var Conversation_FilePhotoOrVideo: String { return self._s[767]! } - public var AccessDenied_Camera: String { return self._s[768]! } - public var Watch_Compose_CurrentLocation: String { return self._s[769]! } - public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[771]! } + public var Notifications_ClassicTones: String { return self._s[753]! } + public var Weekday_ShortWednesday: String { return self._s[754]! } + public var WallpaperPreview_SwipeColorsBottomText: String { return self._s[755]! } + public var Undo_LeftGroup: String { return self._s[758]! } + public var Wallet_RestoreFailed_Text: String { return self._s[759]! } + public var Conversation_LinkDialogCopy: String { return self._s[760]! } + public var Wallet_TransactionInfo_NoAddress: String { return self._s[762]! } + public var Wallet_Navigation_Back: String { return self._s[763]! } + public var KeyCommand_FocusOnInputField: String { return self._s[764]! } + public var Contacts_SelectAll: String { return self._s[765]! } + public var Preview_SaveToCameraRoll: String { return self._s[766]! } + public var PrivacySettings_PasscodeOff: String { return self._s[767]! } + public var Appearance_ThemePreview_ChatList_6_Name: String { return self._s[768]! } + public var Wallpaper_Title: String { return self._s[769]! } + public var Conversation_FilePhotoOrVideo: String { return self._s[770]! } + public var AccessDenied_Camera: String { return self._s[771]! } + public var Watch_Compose_CurrentLocation: String { return self._s[772]! } + public var Channel_DiscussionGroup_MakeHistoryPublicProceed: String { return self._s[774]! } public func SecretImage_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[772]!, self._r[772]!, [_0]) + return formatWithArgumentRanges(self._s[775]!, self._r[775]!, [_0]) } - public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[773]! } - public var Passport_Language_ro: String { return self._s[774]! } - public var EditTheme_UploadNewTheme: String { return self._s[775]! } - public var CheckoutInfo_SaveInfoHelp: String { return self._s[776]! } - public var Wallet_Intro_Terms: String { return self._s[777]! } + public var GroupInfo_InvitationLinkDoesNotExist: String { return self._s[776]! } + public var Passport_Language_ro: String { return self._s[777]! } + public var EditTheme_UploadNewTheme: String { return self._s[778]! } + public var CheckoutInfo_SaveInfoHelp: String { return self._s[779]! } + public var Wallet_Intro_Terms: String { return self._s[780]! } public func Notification_SecretChatMessageScreenshot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[778]!, self._r[778]!, [_0]) + return formatWithArgumentRanges(self._s[781]!, self._r[781]!, [_0]) } - public var Login_CancelPhoneVerification: String { return self._s[779]! } - public var State_ConnectingToProxy: String { return self._s[780]! } - public var Calls_RatingTitle: String { return self._s[781]! } - public var Generic_ErrorMoreInfo: String { return self._s[782]! } - public var ChatList_Search_ShowMore: String { return self._s[783]! } - public var Appearance_PreviewReplyText: String { return self._s[784]! } - public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[785]! } + public var Login_CancelPhoneVerification: String { return self._s[782]! } + public var State_ConnectingToProxy: String { return self._s[783]! } + public var Calls_RatingTitle: String { return self._s[784]! } + public var Generic_ErrorMoreInfo: String { return self._s[785]! } + public var ChatList_Search_ShowMore: String { return self._s[786]! } + public var Appearance_PreviewReplyText: String { return self._s[787]! } + public var CheckoutInfo_ShippingInfoPostcodePlaceholder: String { return self._s[788]! } public func Wallet_Send_Balance(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[786]!, self._r[786]!, [_0]) + return formatWithArgumentRanges(self._s[789]!, self._r[789]!, [_0]) } - public var IntentsSettings_SuggestedChatsContacts: String { return self._s[787]! } - public var SharedMedia_CategoryLinks: String { return self._s[788]! } - public var Calls_Missed: String { return self._s[789]! } - public var Cache_Photos: String { return self._s[793]! } - public var GroupPermission_NoAddMembers: String { return self._s[794]! } - public var ScheduledMessages_Title: String { return self._s[795]! } + public var IntentsSettings_SuggestedChatsContacts: String { return self._s[790]! } + public var SharedMedia_CategoryLinks: String { return self._s[791]! } + public var Calls_Missed: String { return self._s[792]! } + public var Cache_Photos: String { return self._s[796]! } + public var GroupPermission_NoAddMembers: String { return self._s[797]! } + public var ScheduledMessages_Title: String { return self._s[798]! } public func Channel_AdminLog_MessageUnpinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[796]!, self._r[796]!, [_0]) + return formatWithArgumentRanges(self._s[799]!, self._r[799]!, [_0]) } - public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[797]! } - public var Settings_ProxyDisabled: String { return self._s[798]! } + public var Conversation_ShareBotLocationConfirmationTitle: String { return self._s[800]! } + public var Settings_ProxyDisabled: String { return self._s[801]! } public func Settings_ApplyProxyAlertCredentials(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[799]!, self._r[799]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[802]!, self._r[802]!, [_1, _2, _3, _4]) } public func Conversation_RestrictedMediaTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[800]!, self._r[800]!, [_0]) + return formatWithArgumentRanges(self._s[803]!, self._r[803]!, [_0]) } - public var ChatList_Context_RemoveFromRecents: String { return self._s[802]! } - public var Appearance_Title: String { return self._s[803]! } + public var ChatList_Context_RemoveFromRecents: String { return self._s[805]! } + public var Appearance_Title: String { return self._s[806]! } public func Time_MonthOfYear_m2(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[805]!, self._r[805]!, [_0]) + return formatWithArgumentRanges(self._s[808]!, self._r[808]!, [_0]) } - public var Conversation_WalletRequiredText: String { return self._s[806]! } - public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[807]! } - public var OldChannels_NoticeCreateText: String { return self._s[808]! } - public var Channel_EditMessageErrorGeneric: String { return self._s[809]! } - public var Privacy_Calls_IntegrationHelp: String { return self._s[810]! } - public var Preview_DeletePhoto: String { return self._s[811]! } - public var Appearance_AppIconFilledX: String { return self._s[812]! } - public var PrivacySettings_PrivacyTitle: String { return self._s[813]! } + public var Conversation_WalletRequiredText: String { return self._s[809]! } + public var StickerPacksSettings_ShowStickersButtonHelp: String { return self._s[810]! } + public var OldChannels_NoticeCreateText: String { return self._s[811]! } + public var Channel_EditMessageErrorGeneric: String { return self._s[812]! } + public var Privacy_Calls_IntegrationHelp: String { return self._s[813]! } + public var Preview_DeletePhoto: String { return self._s[814]! } + public var Appearance_AppIconFilledX: String { return self._s[815]! } + public var PrivacySettings_PrivacyTitle: String { return self._s[816]! } public func Conversation_BotInteractiveUrlAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[814]!, self._r[814]!, [_0]) + return formatWithArgumentRanges(self._s[817]!, self._r[817]!, [_0]) } - public var Coub_TapForSound: String { return self._s[817]! } - public var Map_LocatingError: String { return self._s[818]! } - public var TwoStepAuth_EmailChangeSuccess: String { return self._s[820]! } - public var Conversation_SendMessage_SendSilently: String { return self._s[821]! } - public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[822]! } + public var Coub_TapForSound: String { return self._s[820]! } + public var Map_LocatingError: String { return self._s[821]! } + public var TwoStepAuth_EmailChangeSuccess: String { return self._s[823]! } + public var Conversation_SendMessage_SendSilently: String { return self._s[824]! } + public var VoiceOver_MessageContextOpenMessageMenu: String { return self._s[825]! } public func Wallet_Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[823]!, self._r[823]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[826]!, self._r[826]!, [_1, _2, _3]) } - public var Passport_ForgottenPassword: String { return self._s[824]! } - public var GroupInfo_InviteLink_RevokeLink: String { return self._s[825]! } - public var StickerPacksSettings_ArchivedPacks: String { return self._s[826]! } - public var Login_TermsOfServiceSignupDecline: String { return self._s[828]! } - public var Channel_Moderator_AccessLevelRevoke: String { return self._s[829]! } - public var Message_Location: String { return self._s[830]! } - public var Passport_Identity_NamePlaceholder: String { return self._s[831]! } - public var Channel_Management_Title: String { return self._s[832]! } - public var DialogList_SearchSectionDialogs: String { return self._s[834]! } - public var Compose_NewChannel_Members: String { return self._s[835]! } + public var Passport_ForgottenPassword: String { return self._s[827]! } + public var GroupInfo_InviteLink_RevokeLink: String { return self._s[828]! } + public var StickerPacksSettings_ArchivedPacks: String { return self._s[829]! } + public var Login_TermsOfServiceSignupDecline: String { return self._s[831]! } + public var Channel_Moderator_AccessLevelRevoke: String { return self._s[832]! } + public var Message_Location: String { return self._s[833]! } + public var Passport_Identity_NamePlaceholder: String { return self._s[834]! } + public var Channel_Management_Title: String { return self._s[835]! } + public var DialogList_SearchSectionDialogs: String { return self._s[837]! } + public var Compose_NewChannel_Members: String { return self._s[838]! } public func DialogList_SingleUploadingFileSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[836]!, self._r[836]!, [_0]) + return formatWithArgumentRanges(self._s[839]!, self._r[839]!, [_0]) } - public var GroupInfo_Location: String { return self._s[837]! } - public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[838]! } - public var ClearCache_Clear: String { return self._s[839]! } - public var AutoNightTheme_ScheduledFrom: String { return self._s[840]! } - public var PhotoEditor_WarmthTool: String { return self._s[841]! } - public var Passport_Language_tr: String { return self._s[842]! } + public var GroupInfo_Location: String { return self._s[840]! } + public var Appearance_ThemePreview_ChatList_5_Name: String { return self._s[841]! } + public var ClearCache_Clear: String { return self._s[842]! } + public var AutoNightTheme_ScheduledFrom: String { return self._s[843]! } + public var PhotoEditor_WarmthTool: String { return self._s[844]! } + public var Passport_Language_tr: String { return self._s[845]! } public func PUSH_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[843]!, self._r[843]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[846]!, self._r[846]!, [_1, _2, _3]) } - public var OldChannels_NoticeUpgradeText: String { return self._s[844]! } - public var Login_ResetAccountProtected_Reset: String { return self._s[846]! } - public var Watch_PhotoView_Title: String { return self._s[847]! } - public var Passport_Phone_Delete: String { return self._s[848]! } - public var Undo_ChatDeletedForBothSides: String { return self._s[849]! } - public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[850]! } - public var GroupInfo_Permissions: String { return self._s[851]! } - public var PasscodeSettings_TurnPasscodeOff: String { return self._s[852]! } - public var Profile_ShareContactButton: String { return self._s[853]! } - public var ChatSettings_Other: String { return self._s[854]! } - public var UserInfo_NotificationsDisabled: String { return self._s[855]! } - public var CheckoutInfo_ShippingInfoCity: String { return self._s[856]! } - public var LastSeen_WithinAMonth: String { return self._s[857]! } - public var VoiceOver_Chat_PlayHint: String { return self._s[858]! } - public var Conversation_ReportGroupLocation: String { return self._s[859]! } - public var Conversation_EncryptionCanceled: String { return self._s[860]! } - public var MediaPicker_GroupDescription: String { return self._s[861]! } - public var WebSearch_Images: String { return self._s[862]! } + public var OldChannels_NoticeUpgradeText: String { return self._s[847]! } + public var Login_ResetAccountProtected_Reset: String { return self._s[849]! } + public var Watch_PhotoView_Title: String { return self._s[850]! } + public var Passport_Phone_Delete: String { return self._s[851]! } + public var Undo_ChatDeletedForBothSides: String { return self._s[852]! } + public var Conversation_EditingMessageMediaEditCurrentPhoto: String { return self._s[853]! } + public var GroupInfo_Permissions: String { return self._s[854]! } + public var PasscodeSettings_TurnPasscodeOff: String { return self._s[855]! } + public var Profile_ShareContactButton: String { return self._s[856]! } + public var ChatSettings_Other: String { return self._s[857]! } + public var UserInfo_NotificationsDisabled: String { return self._s[858]! } + public var CheckoutInfo_ShippingInfoCity: String { return self._s[859]! } + public var LastSeen_WithinAMonth: String { return self._s[860]! } + public var VoiceOver_Chat_PlayHint: String { return self._s[861]! } + public var Conversation_ReportGroupLocation: String { return self._s[862]! } + public var Conversation_EncryptionCanceled: String { return self._s[863]! } + public var MediaPicker_GroupDescription: String { return self._s[864]! } + public var WebSearch_Images: String { return self._s[865]! } public func Channel_Management_PromotedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[863]!, self._r[863]!, [_0]) + return formatWithArgumentRanges(self._s[866]!, self._r[866]!, [_0]) } - public var Message_Photo: String { return self._s[864]! } - public var PasscodeSettings_HelpBottom: String { return self._s[865]! } - public var AutoDownloadSettings_VideosTitle: String { return self._s[866]! } - public var VoiceOver_Media_PlaybackRateChange: String { return self._s[867]! } - public var Passport_Identity_AddDriversLicense: String { return self._s[868]! } - public var TwoStepAuth_EnterPasswordPassword: String { return self._s[869]! } - public var NotificationsSound_Calypso: String { return self._s[870]! } - public var Map_Map: String { return self._s[871]! } + public var Message_Photo: String { return self._s[867]! } + public var PasscodeSettings_HelpBottom: String { return self._s[868]! } + public var AutoDownloadSettings_VideosTitle: String { return self._s[869]! } + public var VoiceOver_Media_PlaybackRateChange: String { return self._s[870]! } + public var Passport_Identity_AddDriversLicense: String { return self._s[871]! } + public var TwoStepAuth_EnterPasswordPassword: String { return self._s[872]! } + public var NotificationsSound_Calypso: String { return self._s[873]! } + public var Map_Map: String { return self._s[874]! } public func Conversation_LiveLocationYouAndOther(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[872]!, self._r[872]!, [_0]) + return formatWithArgumentRanges(self._s[875]!, self._r[875]!, [_0]) } - public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[874]! } - public var ChatSettings_TextSizeUnits: String { return self._s[875]! } + public var CheckoutInfo_ReceiverInfoTitle: String { return self._s[877]! } + public var ChatSettings_TextSizeUnits: String { return self._s[878]! } public func VoiceOver_Chat_FileFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[876]!, self._r[876]!, [_0]) + return formatWithArgumentRanges(self._s[879]!, self._r[879]!, [_0]) } - public var Common_of: String { return self._s[877]! } - public var Conversation_ForwardContacts: String { return self._s[880]! } - public var IntentsSettings_SuggestByAll: String { return self._s[882]! } + public var Common_of: String { return self._s[880]! } + public var Conversation_ForwardContacts: String { return self._s[883]! } + public var IntentsSettings_SuggestByAll: String { return self._s[885]! } public func Call_AnsweringWithAccount(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[883]!, self._r[883]!, [_0]) + return formatWithArgumentRanges(self._s[886]!, self._r[886]!, [_0]) } - public var Passport_Language_hy: String { return self._s[884]! } - public var Notifications_MessageNotificationsHelp: String { return self._s[885]! } - public var AutoDownloadSettings_Reset: String { return self._s[886]! } - public var Wallet_TransactionInfo_AddressCopied: String { return self._s[887]! } - public var Paint_ClearConfirm: String { return self._s[888]! } - public var Camera_VideoMode: String { return self._s[889]! } + public var Passport_Language_hy: String { return self._s[887]! } + public var Notifications_MessageNotificationsHelp: String { return self._s[888]! } + public var AutoDownloadSettings_Reset: String { return self._s[889]! } + public var Wallet_TransactionInfo_AddressCopied: String { return self._s[890]! } + public var Paint_ClearConfirm: String { return self._s[891]! } + public var Camera_VideoMode: String { return self._s[892]! } public func Conversation_RestrictedStickersTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[890]!, self._r[890]!, [_0]) + return formatWithArgumentRanges(self._s[893]!, self._r[893]!, [_0]) } - public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[891]! } - public var Conversation_ViewBackground: String { return self._s[892]! } + public var Privacy_Calls_AlwaysAllow_Placeholder: String { return self._s[894]! } + public var Conversation_ViewBackground: String { return self._s[895]! } public func Wallet_Info_TransactionDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[893]!, self._r[893]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[896]!, self._r[896]!, [_1, _2, _3]) } - public var Passport_Language_el: String { return self._s[894]! } - public var PhotoEditor_Original: String { return self._s[895]! } - public var Settings_FAQ_Button: String { return self._s[897]! } - public var Channel_Setup_PublicNoLink: String { return self._s[899]! } - public var Conversation_UnsupportedMedia: String { return self._s[900]! } - public var Conversation_SlideToCancel: String { return self._s[901]! } - public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[902]! } - public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[903]! } - public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[904]! } - public var Conversation_ReportSpamChannelConfirmation: String { return self._s[905]! } - public var AutoNightTheme_NotAvailable: String { return self._s[906]! } - public var Conversation_Owner: String { return self._s[907]! } - public var Common_Create: String { return self._s[908]! } - public var Settings_ApplyProxyAlertEnable: String { return self._s[909]! } - public var ContactList_Context_Call: String { return self._s[910]! } - public var Localization_ChooseLanguage: String { return self._s[912]! } - public var ChatList_Context_AddToContacts: String { return self._s[914]! } - public var OldChannels_NoticeTitle: String { return self._s[915]! } - public var Settings_Proxy: String { return self._s[917]! } - public var Privacy_TopPeersHelp: String { return self._s[918]! } - public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[919]! } - public var Chat_UnsendMyMessages: String { return self._s[920]! } + public var Passport_Language_el: String { return self._s[897]! } + public var PhotoEditor_Original: String { return self._s[898]! } + public var Settings_FAQ_Button: String { return self._s[900]! } + public var Channel_Setup_PublicNoLink: String { return self._s[902]! } + public var Conversation_UnsupportedMedia: String { return self._s[903]! } + public var Conversation_SlideToCancel: String { return self._s[904]! } + public var Appearance_ThemePreview_ChatList_4_Name: String { return self._s[905]! } + public var Passport_Identity_OneOfTypeInternalPassport: String { return self._s[906]! } + public var CheckoutInfo_ShippingInfoPostcode: String { return self._s[907]! } + public var Conversation_ReportSpamChannelConfirmation: String { return self._s[908]! } + public var AutoNightTheme_NotAvailable: String { return self._s[909]! } + public var Conversation_Owner: String { return self._s[910]! } + public var Common_Create: String { return self._s[911]! } + public var Settings_ApplyProxyAlertEnable: String { return self._s[912]! } + public var ContactList_Context_Call: String { return self._s[913]! } + public var Localization_ChooseLanguage: String { return self._s[915]! } + public var ChatList_Context_AddToContacts: String { return self._s[917]! } + public var OldChannels_NoticeTitle: String { return self._s[918]! } + public var Settings_Proxy: String { return self._s[920]! } + public var Privacy_TopPeersHelp: String { return self._s[921]! } + public var CheckoutInfo_ShippingInfoCountryPlaceholder: String { return self._s[922]! } + public var Chat_UnsendMyMessages: String { return self._s[923]! } public func VoiceOver_Chat_Duration(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[921]!, self._r[921]!, [_0]) - } - public var TwoStepAuth_ConfirmationAbort: String { return self._s[922]! } - public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[924]!, self._r[924]!, [_0]) } - public var Contacts_SortedByPresence: String { return self._s[925]! } - public var Passport_Identity_SurnamePlaceholder: String { return self._s[926]! } - public var Cache_Title: String { return self._s[927]! } + public var TwoStepAuth_ConfirmationAbort: String { return self._s[925]! } + public func Contacts_AccessDeniedHelpPortrait(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[927]!, self._r[927]!, [_0]) + } + public var Contacts_SortedByPresence: String { return self._s[928]! } + public var Passport_Identity_SurnamePlaceholder: String { return self._s[929]! } + public var Cache_Title: String { return self._s[930]! } public func Login_PhoneBannedEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[928]!, self._r[928]!, [_0]) + return formatWithArgumentRanges(self._s[931]!, self._r[931]!, [_0]) } - public var TwoStepAuth_EmailCodeExpired: String { return self._s[929]! } - public var Channel_Moderator_Title: String { return self._s[930]! } - public var InstantPage_AutoNightTheme: String { return self._s[932]! } + public var TwoStepAuth_EmailCodeExpired: String { return self._s[932]! } + public var Channel_Moderator_Title: String { return self._s[933]! } + public var InstantPage_AutoNightTheme: String { return self._s[935]! } public func PUSH_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[935]!, self._r[935]!, [_1]) + return formatWithArgumentRanges(self._s[938]!, self._r[938]!, [_1]) } - public var Passport_Scans_Upload: String { return self._s[936]! } - public var Undo_Undo: String { return self._s[938]! } - public var Contacts_AccessDeniedHelpON: String { return self._s[939]! } - public var TwoStepAuth_RemovePassword: String { return self._s[940]! } - public var Common_Delete: String { return self._s[941]! } - public var Contacts_AddPeopleNearby: String { return self._s[943]! } - public var Conversation_ContextMenuDelete: String { return self._s[944]! } - public var SocksProxySetup_Credentials: String { return self._s[945]! } - public var Appearance_EditTheme: String { return self._s[947]! } - public var ClearCache_StorageOtherApps: String { return self._s[948]! } - public var PasscodeSettings_AutoLock_Disabled: String { return self._s[949]! } - public var Wallet_Send_NetworkErrorText: String { return self._s[950]! } - public var AuthSessions_DevicesTitle: String { return self._s[952]! } - public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[954]! } - public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[955]! } - public var Passport_Language_id: String { return self._s[957]! } - public var WallpaperSearch_ColorTeal: String { return self._s[958]! } - public var ChannelIntro_Title: String { return self._s[959]! } + public var Passport_Scans_Upload: String { return self._s[939]! } + public var Undo_Undo: String { return self._s[941]! } + public var Contacts_AccessDeniedHelpON: String { return self._s[942]! } + public var TwoStepAuth_RemovePassword: String { return self._s[943]! } + public var Common_Delete: String { return self._s[944]! } + public var Contacts_AddPeopleNearby: String { return self._s[946]! } + public var Conversation_ContextMenuDelete: String { return self._s[947]! } + public var SocksProxySetup_Credentials: String { return self._s[948]! } + public var Appearance_EditTheme: String { return self._s[950]! } + public var ClearCache_StorageOtherApps: String { return self._s[951]! } + public var PasscodeSettings_AutoLock_Disabled: String { return self._s[952]! } + public var Wallet_Send_NetworkErrorText: String { return self._s[953]! } + public var AuthSessions_DevicesTitle: String { return self._s[955]! } + public var Passport_Address_OneOfTypeRentalAgreement: String { return self._s[957]! } + public var Conversation_ShareBotContactConfirmationTitle: String { return self._s[958]! } + public var Passport_Language_id: String { return self._s[960]! } + public var WallpaperSearch_ColorTeal: String { return self._s[961]! } + public var ChannelIntro_Title: String { return self._s[962]! } public func Channel_AdminLog_MessageToggleSignaturesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[960]!, self._r[960]!, [_0]) + return formatWithArgumentRanges(self._s[963]!, self._r[963]!, [_0]) } - public var VoiceOver_Chat_OpenLinkHint: String { return self._s[962]! } - public var VoiceOver_Chat_Reply: String { return self._s[963]! } - public var ScheduledMessages_BotActionUnavailable: String { return self._s[964]! } - public var Channel_Info_Description: String { return self._s[965]! } - public var Stickers_FavoriteStickers: String { return self._s[966]! } - public var Channel_BanUser_PermissionAddMembers: String { return self._s[967]! } - public var Notifications_DisplayNamesOnLockScreen: String { return self._s[968]! } - public var ChatSearch_ResultsTooltip: String { return self._s[969]! } - public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[970]! } - public var Calls_NoMissedCallsPlacehoder: String { return self._s[971]! } - public var Group_PublicLink_Placeholder: String { return self._s[972]! } - public var Notifications_ExceptionsDefaultSound: String { return self._s[973]! } + public var VoiceOver_Chat_OpenLinkHint: String { return self._s[965]! } + public var VoiceOver_Chat_Reply: String { return self._s[966]! } + public var ScheduledMessages_BotActionUnavailable: String { return self._s[967]! } + public var Channel_Info_Description: String { return self._s[968]! } + public var Stickers_FavoriteStickers: String { return self._s[969]! } + public var Channel_BanUser_PermissionAddMembers: String { return self._s[970]! } + public var Notifications_DisplayNamesOnLockScreen: String { return self._s[971]! } + public var ChatSearch_ResultsTooltip: String { return self._s[972]! } + public var Wallet_VoiceOver_Editing_ClearText: String { return self._s[973]! } + public var Calls_NoMissedCallsPlacehoder: String { return self._s[974]! } + public var Group_PublicLink_Placeholder: String { return self._s[975]! } + public var Notifications_ExceptionsDefaultSound: String { return self._s[976]! } public func PUSH_CHANNEL_MESSAGE_POLL(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[974]!, self._r[974]!, [_1]) + return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_1]) } - public var TextFormat_Underline: String { return self._s[975]! } + public var TextFormat_Underline: String { return self._s[978]! } public func DialogList_SearchSubtitleFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[977]!, self._r[977]!, [_1, _2]) - } - public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[978]!, self._r[978]!, [_0]) - } - public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[979]! } - public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[980]!, self._r[980]!, [_1, _2]) } - public var Wallet_Intro_ImportExisting: String { return self._s[981]! } - public var GroupPermission_Delete: String { return self._s[982]! } - public var Passport_Language_uk: String { return self._s[983]! } - public var StickerPack_HideStickers: String { return self._s[985]! } - public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[986]! } + public func Channel_AdminLog_MessageRemovedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[981]!, self._r[981]!, [_0]) + } + public var Appearance_ThemePreview_ChatList_3_Name: String { return self._s[982]! } + public func Channel_OwnershipTransfer_TransferCompleted(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[983]!, self._r[983]!, [_1, _2]) + } + public var Wallet_Intro_ImportExisting: String { return self._s[984]! } + public var GroupPermission_Delete: String { return self._s[985]! } + public var Passport_Language_uk: String { return self._s[986]! } + public var StickerPack_HideStickers: String { return self._s[988]! } + public var ChangePhoneNumberNumber_NumberPlaceholder: String { return self._s[989]! } public func PUSH_CHAT_MESSAGE_PHOTO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[987]!, self._r[987]!, [_1, _2]) + return formatWithArgumentRanges(self._s[990]!, self._r[990]!, [_1, _2]) } - public var Activity_UploadingVideoMessage: String { return self._s[988]! } + public var Activity_UploadingVideoMessage: String { return self._s[991]! } public func GroupPermission_ApplyAlertText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[989]!, self._r[989]!, [_0]) + return formatWithArgumentRanges(self._s[992]!, self._r[992]!, [_0]) } - public var Channel_TitleInfo: String { return self._s[990]! } - public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[991]! } - public var Settings_CallSettings: String { return self._s[992]! } - public var Camera_SquareMode: String { return self._s[993]! } - public var Conversation_SendMessage_ScheduleMessage: String { return self._s[994]! } - public var GroupInfo_SharedMediaNone: String { return self._s[995]! } + public var Channel_TitleInfo: String { return self._s[993]! } + public var StickerPacksSettings_ArchivedPacks_Info: String { return self._s[994]! } + public var Settings_CallSettings: String { return self._s[995]! } + public var Camera_SquareMode: String { return self._s[996]! } + public var Conversation_SendMessage_ScheduleMessage: String { return self._s[997]! } + public var GroupInfo_SharedMediaNone: String { return self._s[998]! } public func PUSH_MESSAGE_VIDEO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[996]!, self._r[996]!, [_1]) + return formatWithArgumentRanges(self._s[999]!, self._r[999]!, [_1]) } - public var Bot_GenericBotStatus: String { return self._s[997]! } - public var Application_Update: String { return self._s[999]! } - public var Month_ShortJanuary: String { return self._s[1000]! } - public var Contacts_PermissionsKeepDisabled: String { return self._s[1001]! } - public var Channel_AdminLog_BanReadMessages: String { return self._s[1002]! } - public var Settings_AppLanguage_Unofficial: String { return self._s[1003]! } - public var Passport_Address_Street2Placeholder: String { return self._s[1004]! } + public var Bot_GenericBotStatus: String { return self._s[1000]! } + public var Application_Update: String { return self._s[1002]! } + public var Month_ShortJanuary: String { return self._s[1003]! } + public var Contacts_PermissionsKeepDisabled: String { return self._s[1004]! } + public var Channel_AdminLog_BanReadMessages: String { return self._s[1005]! } + public var Settings_AppLanguage_Unofficial: String { return self._s[1006]! } + public var Passport_Address_Street2Placeholder: String { return self._s[1007]! } public func Map_LiveLocationShortHour(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1005]!, self._r[1005]!, [_0]) - } - public var NetworkUsageSettings_Cellular: String { return self._s[1006]! } - public var Appearance_PreviewOutgoingText: String { return self._s[1007]! } - public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1008]!, self._r[1008]!, [_0]) } - public var Notifications_PermissionsAllowInSettings: String { return self._s[1009]! } - public var AutoDownloadSettings_OnForAll: String { return self._s[1011]! } - public var Map_Directions: String { return self._s[1012]! } - public var Passport_FieldIdentityTranslationHelp: String { return self._s[1014]! } - public var Appearance_ThemeDay: String { return self._s[1015]! } - public var LogoutOptions_LogOut: String { return self._s[1016]! } - public var Group_PublicLink_Title: String { return self._s[1018]! } - public var Channel_AddBotErrorNoRights: String { return self._s[1019]! } - public var ChatList_Search_ShowLess: String { return self._s[1020]! } - public var Passport_Identity_AddPassport: String { return self._s[1021]! } - public var LocalGroup_ButtonTitle: String { return self._s[1022]! } - public var Call_Message: String { return self._s[1023]! } - public var PhotoEditor_ExposureTool: String { return self._s[1024]! } - public var Wallet_Receive_CommentInfo: String { return self._s[1026]! } - public var Passport_FieldOneOf_Delimeter: String { return self._s[1027]! } - public var Channel_AdminLog_CanBanUsers: String { return self._s[1029]! } - public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1030]! } - public var Appearance_Preview: String { return self._s[1031]! } - public var Compose_ChannelMembers: String { return self._s[1032]! } - public var Conversation_DeleteManyMessages: String { return self._s[1033]! } - public var ReportPeer_ReasonOther_Title: String { return self._s[1034]! } - public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1035]! } - public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1036]! } - public var Channel_Stickers_CreateYourOwn: String { return self._s[1039]! } - public var Conversation_UpdateTelegram: String { return self._s[1040]! } - public var EditTheme_Create_TopInfo: String { return self._s[1041]! } + public var NetworkUsageSettings_Cellular: String { return self._s[1009]! } + public var Appearance_PreviewOutgoingText: String { return self._s[1010]! } + public func StickerPackActionInfo_RemovedText(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1011]!, self._r[1011]!, [_0]) + } + public var Notifications_PermissionsAllowInSettings: String { return self._s[1012]! } + public var AutoDownloadSettings_OnForAll: String { return self._s[1014]! } + public var Map_Directions: String { return self._s[1015]! } + public var Passport_FieldIdentityTranslationHelp: String { return self._s[1017]! } + public var Appearance_ThemeDay: String { return self._s[1018]! } + public var LogoutOptions_LogOut: String { return self._s[1019]! } + public var Group_PublicLink_Title: String { return self._s[1021]! } + public var Channel_AddBotErrorNoRights: String { return self._s[1022]! } + public var ChatList_Search_ShowLess: String { return self._s[1023]! } + public var Passport_Identity_AddPassport: String { return self._s[1024]! } + public var LocalGroup_ButtonTitle: String { return self._s[1025]! } + public var Call_Message: String { return self._s[1026]! } + public var PhotoEditor_ExposureTool: String { return self._s[1027]! } + public var Wallet_Receive_CommentInfo: String { return self._s[1029]! } + public var Passport_FieldOneOf_Delimeter: String { return self._s[1030]! } + public var Channel_AdminLog_CanBanUsers: String { return self._s[1032]! } + public var Appearance_ThemePreview_ChatList_2_Name: String { return self._s[1033]! } + public var Appearance_Preview: String { return self._s[1034]! } + public var Compose_ChannelMembers: String { return self._s[1035]! } + public var Conversation_DeleteManyMessages: String { return self._s[1036]! } + public var ReportPeer_ReasonOther_Title: String { return self._s[1037]! } + public var Checkout_ErrorProviderAccountTimeout: String { return self._s[1038]! } + public var TwoStepAuth_ResetAccountConfirmation: String { return self._s[1039]! } + public var Channel_Stickers_CreateYourOwn: String { return self._s[1042]! } + public var Conversation_UpdateTelegram: String { return self._s[1043]! } + public var EditTheme_Create_TopInfo: String { return self._s[1044]! } public func Notification_PinnedPhotoMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1042]!, self._r[1042]!, [_0]) + return formatWithArgumentRanges(self._s[1045]!, self._r[1045]!, [_0]) } - public var Wallet_WordCheck_Continue: String { return self._s[1043]! } - public var TwoFactorSetup_Hint_Action: String { return self._s[1044]! } - public var IntentsSettings_ResetAll: String { return self._s[1045]! } + public var Wallet_WordCheck_Continue: String { return self._s[1046]! } + public var TwoFactorSetup_Hint_Action: String { return self._s[1047]! } + public var IntentsSettings_ResetAll: String { return self._s[1048]! } public func PUSH_PINNED_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1046]!, self._r[1046]!, [_1]) + return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_1]) } - public var GroupInfo_Administrators_Title: String { return self._s[1047]! } - public var Privacy_Forwards_PreviewMessageText: String { return self._s[1048]! } + public var GroupInfo_Administrators_Title: String { return self._s[1050]! } + public var Privacy_Forwards_PreviewMessageText: String { return self._s[1051]! } public func PrivacySettings_LastSeenNobodyPlus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1049]!, self._r[1049]!, [_0]) + return formatWithArgumentRanges(self._s[1052]!, self._r[1052]!, [_0]) } - public var Tour_Title3: String { return self._s[1050]! } - public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1051]! } - public var Clipboard_SendPhoto: String { return self._s[1055]! } - public var MediaPicker_Videos: String { return self._s[1056]! } - public var Passport_Email_Title: String { return self._s[1057]! } + public var Tour_Title3: String { return self._s[1053]! } + public var Channel_EditAdmin_PermissionInviteSubscribers: String { return self._s[1054]! } + public var Clipboard_SendPhoto: String { return self._s[1058]! } + public var MediaPicker_Videos: String { return self._s[1059]! } + public var Passport_Email_Title: String { return self._s[1060]! } public func PrivacySettings_LastSeenEverybodyMinus(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1058]!, self._r[1058]!, [_0]) + return formatWithArgumentRanges(self._s[1061]!, self._r[1061]!, [_0]) } - public var StickerPacksSettings_Title: String { return self._s[1059]! } - public var Conversation_MessageDialogDelete: String { return self._s[1060]! } - public var Privacy_Calls_CustomHelp: String { return self._s[1062]! } - public var Message_Wallpaper: String { return self._s[1063]! } - public var MemberSearch_BotSection: String { return self._s[1064]! } - public var GroupInfo_SetSound: String { return self._s[1065]! } - public var Core_ServiceUserStatus: String { return self._s[1066]! } - public var LiveLocationUpdated_JustNow: String { return self._s[1067]! } - public var Call_StatusFailed: String { return self._s[1068]! } - public var TwoFactorSetup_Email_Placeholder: String { return self._s[1069]! } - public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1070]! } - public var TwoStepAuth_SetPassword: String { return self._s[1071]! } - public var Permissions_PeopleNearbyText_v0: String { return self._s[1072]! } + public var StickerPacksSettings_Title: String { return self._s[1062]! } + public var Conversation_MessageDialogDelete: String { return self._s[1063]! } + public var Privacy_Calls_CustomHelp: String { return self._s[1065]! } + public var Message_Wallpaper: String { return self._s[1066]! } + public var MemberSearch_BotSection: String { return self._s[1067]! } + public var GroupInfo_SetSound: String { return self._s[1068]! } + public func Time_TomorrowAt(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1069]!, self._r[1069]!, [_0]) + } + public var Core_ServiceUserStatus: String { return self._s[1070]! } + public var LiveLocationUpdated_JustNow: String { return self._s[1071]! } + public var Call_StatusFailed: String { return self._s[1072]! } + public var TwoFactorSetup_Email_Placeholder: String { return self._s[1073]! } + public var TwoStepAuth_SetupPasswordDescription: String { return self._s[1074]! } + public var TwoStepAuth_SetPassword: String { return self._s[1075]! } + public var Permissions_PeopleNearbyText_v0: String { return self._s[1076]! } public func SocksProxySetup_ProxyStatusPing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1074]!, self._r[1074]!, [_0]) + return formatWithArgumentRanges(self._s[1078]!, self._r[1078]!, [_0]) } - public var Calls_SubmitRating: String { return self._s[1075]! } - public var Map_NoPlacesNearby: String { return self._s[1076]! } - public var Profile_Username: String { return self._s[1077]! } - public var Bot_DescriptionTitle: String { return self._s[1078]! } - public var MaskStickerSettings_Title: String { return self._s[1079]! } - public var SharedMedia_CategoryOther: String { return self._s[1080]! } - public var GroupInfo_SetGroupPhoto: String { return self._s[1081]! } - public var Common_NotNow: String { return self._s[1082]! } - public var CallFeedback_IncludeLogsInfo: String { return self._s[1083]! } - public var Conversation_ShareMyPhoneNumber: String { return self._s[1084]! } - public var Map_Location: String { return self._s[1085]! } - public var Invitation_JoinGroup: String { return self._s[1086]! } - public var AutoDownloadSettings_Title: String { return self._s[1088]! } - public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1089]! } - public var Channel_ErrorAddBlocked: String { return self._s[1090]! } - public var Conversation_UnblockUser: String { return self._s[1091]! } - public var EditTheme_Edit_TopInfo: String { return self._s[1092]! } - public var Watch_Bot_Restart: String { return self._s[1093]! } - public var TwoStepAuth_Title: String { return self._s[1094]! } - public var Channel_AdminLog_BanSendMessages: String { return self._s[1095]! } - public var Checkout_ShippingMethod: String { return self._s[1096]! } - public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1097]! } + public var Calls_SubmitRating: String { return self._s[1079]! } + public var Map_NoPlacesNearby: String { return self._s[1080]! } + public var Profile_Username: String { return self._s[1081]! } + public var Bot_DescriptionTitle: String { return self._s[1082]! } + public var MaskStickerSettings_Title: String { return self._s[1083]! } + public var SharedMedia_CategoryOther: String { return self._s[1084]! } + public var GroupInfo_SetGroupPhoto: String { return self._s[1085]! } + public var Common_NotNow: String { return self._s[1086]! } + public var CallFeedback_IncludeLogsInfo: String { return self._s[1087]! } + public var Conversation_ShareMyPhoneNumber: String { return self._s[1088]! } + public var Map_Location: String { return self._s[1089]! } + public var Invitation_JoinGroup: String { return self._s[1090]! } + public var AutoDownloadSettings_Title: String { return self._s[1092]! } + public var Conversation_DiscardVoiceMessageDescription: String { return self._s[1093]! } + public var Channel_ErrorAddBlocked: String { return self._s[1094]! } + public var Conversation_UnblockUser: String { return self._s[1095]! } + public var EditTheme_Edit_TopInfo: String { return self._s[1096]! } + public var Watch_Bot_Restart: String { return self._s[1097]! } + public var TwoStepAuth_Title: String { return self._s[1098]! } + public var Channel_AdminLog_BanSendMessages: String { return self._s[1099]! } + public var Checkout_ShippingMethod: String { return self._s[1100]! } + public var Passport_Identity_OneOfTypeIdentityCard: String { return self._s[1101]! } public func PUSH_CHAT_MESSAGE_STICKER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1098]!, self._r[1098]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_1, _2, _3]) } - public var EditTheme_ChangeColors: String { return self._s[1100]! } + public var EditTheme_ChangeColors: String { return self._s[1104]! } public func Chat_UnsendMyMessagesAlertTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1101]!, self._r[1101]!, [_0]) + return formatWithArgumentRanges(self._s[1105]!, self._r[1105]!, [_0]) } public func Channel_Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1102]!, self._r[1102]!, [_0]) + return formatWithArgumentRanges(self._s[1106]!, self._r[1106]!, [_0]) } - public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1103]! } - public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1104]! } - public var AuthSessions_TerminateOtherSessions: String { return self._s[1105]! } - public var Contacts_FailedToSendInvitesMessage: String { return self._s[1106]! } - public var PrivacySettings_TwoStepAuth: String { return self._s[1107]! } - public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1108]! } - public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1109]! } - public var Conversation_EditingMessagePanelMedia: String { return self._s[1110]! } - public var Checkout_PaymentMethod_Title: String { return self._s[1111]! } - public var SocksProxySetup_Connection: String { return self._s[1112]! } - public var Group_MessagePhotoRemoved: String { return self._s[1113]! } - public var Channel_Stickers_NotFound: String { return self._s[1116]! } - public var Group_About_Help: String { return self._s[1117]! } - public var Notification_PassportValueProofOfIdentity: String { return self._s[1118]! } - public var PeopleNearby_Title: String { return self._s[1120]! } + public var Appearance_ThemePreview_ChatList_1_Name: String { return self._s[1107]! } + public var SettingsSearch_Synonyms_Data_AutoplayGifs: String { return self._s[1108]! } + public var AuthSessions_TerminateOtherSessions: String { return self._s[1109]! } + public var Contacts_FailedToSendInvitesMessage: String { return self._s[1110]! } + public var PrivacySettings_TwoStepAuth: String { return self._s[1111]! } + public var Notification_Exceptions_PreviewAlwaysOn: String { return self._s[1112]! } + public var SettingsSearch_Synonyms_Privacy_Passcode: String { return self._s[1113]! } + public var Conversation_EditingMessagePanelMedia: String { return self._s[1114]! } + public var Checkout_PaymentMethod_Title: String { return self._s[1115]! } + public var SocksProxySetup_Connection: String { return self._s[1116]! } + public var Group_MessagePhotoRemoved: String { return self._s[1117]! } + public var PeopleNearby_MakeInvisible: String { return self._s[1119]! } + public var Channel_Stickers_NotFound: String { return self._s[1121]! } + public var Group_About_Help: String { return self._s[1122]! } + public var Notification_PassportValueProofOfIdentity: String { return self._s[1123]! } + public var PeopleNearby_Title: String { return self._s[1125]! } public func ApplyLanguage_ChangeLanguageOfficialText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1121]!, self._r[1121]!, [_1]) + return formatWithArgumentRanges(self._s[1126]!, self._r[1126]!, [_1]) } - public var Map_Home: String { return self._s[1122]! } - public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1124]! } - public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1125]! } - public var SocksProxySetup_Password: String { return self._s[1126]! } - public var Notifications_PermissionsEnable: String { return self._s[1127]! } - public var TwoStepAuth_ChangeEmail: String { return self._s[1129]! } + public var Map_Home: String { return self._s[1127]! } + public var CheckoutInfo_ShippingInfoStatePlaceholder: String { return self._s[1129]! } + public var Notifications_GroupNotificationsExceptionsHelp: String { return self._s[1130]! } + public var SocksProxySetup_Password: String { return self._s[1131]! } + public var Notifications_PermissionsEnable: String { return self._s[1132]! } + public var TwoStepAuth_ChangeEmail: String { return self._s[1134]! } public func Channel_AdminLog_MessageInvitedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1130]!, self._r[1130]!, [_1]) + return formatWithArgumentRanges(self._s[1135]!, self._r[1135]!, [_1]) } public func Time_MonthOfYear_m10(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1132]!, self._r[1132]!, [_0]) + return formatWithArgumentRanges(self._s[1137]!, self._r[1137]!, [_0]) } - public var Passport_Identity_TypeDriversLicense: String { return self._s[1133]! } - public var ArchivedPacksAlert_Title: String { return self._s[1134]! } - public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1135]! } - public var Map_PlacesNearby: String { return self._s[1136]! } + public var Passport_Identity_TypeDriversLicense: String { return self._s[1138]! } + public var ArchivedPacksAlert_Title: String { return self._s[1139]! } + public var Wallet_Receive_InvoiceUrlCopied: String { return self._s[1140]! } + public var Map_PlacesNearby: String { return self._s[1141]! } public func Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1137]!, self._r[1137]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1142]!, self._r[1142]!, [_1, _2, _3]) } - public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1138]! } - public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1140]! } - public var Conversation_StatusTyping: String { return self._s[1141]! } - public var Broadcast_AdminLog_EmptyText: String { return self._s[1142]! } - public var Notification_PassportValueProofOfAddress: String { return self._s[1143]! } - public var UserInfo_CreateNewContact: String { return self._s[1144]! } - public var Passport_Identity_FrontSide: String { return self._s[1145]! } - public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1146]! } - public var Calls_CallTabTitle: String { return self._s[1147]! } - public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1148]! } + public var PrivacyLastSeenSettings_GroupsAndChannelsHelp: String { return self._s[1143]! } + public var Privacy_Calls_NeverAllow_Placeholder: String { return self._s[1145]! } + public var Conversation_StatusTyping: String { return self._s[1146]! } + public var Broadcast_AdminLog_EmptyText: String { return self._s[1147]! } + public var Notification_PassportValueProofOfAddress: String { return self._s[1148]! } + public var UserInfo_CreateNewContact: String { return self._s[1149]! } + public var Passport_Identity_FrontSide: String { return self._s[1150]! } + public var Login_PhoneNumberAlreadyAuthorizedSwitch: String { return self._s[1151]! } + public var Calls_CallTabTitle: String { return self._s[1152]! } + public var Channel_AdminLog_ChannelEmptyText: String { return self._s[1153]! } public func Login_BannedPhoneBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1150]!, self._r[1150]!, [_0]) + return formatWithArgumentRanges(self._s[1155]!, self._r[1155]!, [_0]) } - public var Watch_UserInfo_MuteTitle: String { return self._s[1151]! } - public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1152]! } - public var SharedMedia_EmptyMusicText: String { return self._s[1153]! } - public var Wallet_Completed_Text: String { return self._s[1154]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1155]! } - public var Paint_Stickers: String { return self._s[1156]! } - public var Privacy_GroupsAndChannels: String { return self._s[1157]! } - public var ChatList_Context_Delete: String { return self._s[1159]! } - public var UserInfo_AddContact: String { return self._s[1160]! } + public var Watch_UserInfo_MuteTitle: String { return self._s[1156]! } + public var Group_EditAdmin_RankAdminPlaceholder: String { return self._s[1157]! } + public var SharedMedia_EmptyMusicText: String { return self._s[1158]! } + public var Wallet_Completed_Text: String { return self._s[1159]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1minute: String { return self._s[1160]! } + public var Paint_Stickers: String { return self._s[1161]! } + public var Privacy_GroupsAndChannels: String { return self._s[1162]! } + public var ChatList_Context_Delete: String { return self._s[1164]! } + public var UserInfo_AddContact: String { return self._s[1165]! } public func Conversation_MessageViaUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1161]!, self._r[1161]!, [_0]) + return formatWithArgumentRanges(self._s[1166]!, self._r[1166]!, [_0]) } - public var PhoneNumberHelp_ChangeNumber: String { return self._s[1163]! } + public var PhoneNumberHelp_ChangeNumber: String { return self._s[1168]! } public func ChatList_ClearChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1165]!, self._r[1165]!, [_0]) + return formatWithArgumentRanges(self._s[1170]!, self._r[1170]!, [_0]) } - public var DialogList_NoMessagesTitle: String { return self._s[1166]! } - public var EditProfile_NameAndPhotoHelp: String { return self._s[1167]! } - public var BlockedUsers_BlockUser: String { return self._s[1168]! } - public var Notifications_PermissionsOpenSettings: String { return self._s[1169]! } - public var MediaPicker_UngroupDescription: String { return self._s[1171]! } - public var Watch_NoConnection: String { return self._s[1172]! } - public var Month_GenSeptember: String { return self._s[1173]! } - public var Conversation_ViewGroup: String { return self._s[1175]! } - public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1178]! } - public var Privacy_Forwards_AlwaysLink: String { return self._s[1179]! } - public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1180]! } - public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1181]! } - public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1182]! } - public var MediaPicker_CameraRoll: String { return self._s[1184]! } - public var Month_GenAugust: String { return self._s[1185]! } - public var Wallet_Configuration_SourceHeader: String { return self._s[1186]! } - public var AccessDenied_VideoMessageMicrophone: String { return self._s[1187]! } - public var SharedMedia_EmptyText: String { return self._s[1188]! } - public var Map_ShareLiveLocation: String { return self._s[1189]! } - public var Calls_All: String { return self._s[1190]! } - public var Map_SendThisPlace: String { return self._s[1192]! } - public var Appearance_ThemeNight: String { return self._s[1194]! } - public var Conversation_HoldForAudio: String { return self._s[1195]! } - public var SettingsSearch_Synonyms_Support: String { return self._s[1198]! } - public var GroupInfo_GroupHistoryHidden: String { return self._s[1199]! } - public var SocksProxySetup_Secret: String { return self._s[1200]! } + public var DialogList_NoMessagesTitle: String { return self._s[1171]! } + public var EditProfile_NameAndPhotoHelp: String { return self._s[1172]! } + public var BlockedUsers_BlockUser: String { return self._s[1173]! } + public var Notifications_PermissionsOpenSettings: String { return self._s[1174]! } + public var MediaPicker_UngroupDescription: String { return self._s[1176]! } + public var Watch_NoConnection: String { return self._s[1177]! } + public var Month_GenSeptember: String { return self._s[1178]! } + public var Conversation_ViewGroup: String { return self._s[1180]! } + public var Channel_AdminLogFilter_EventsLeavingSubscribers: String { return self._s[1183]! } + public var Privacy_Forwards_AlwaysLink: String { return self._s[1184]! } + public var Channel_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[1185]! } + public var Passport_FieldOneOf_FinalDelimeter: String { return self._s[1186]! } + public var Wallet_WordCheck_IncorrectHeader: String { return self._s[1187]! } + public var MediaPicker_CameraRoll: String { return self._s[1189]! } + public var Month_GenAugust: String { return self._s[1190]! } + public var Wallet_Configuration_SourceHeader: String { return self._s[1191]! } + public var AccessDenied_VideoMessageMicrophone: String { return self._s[1192]! } + public var SharedMedia_EmptyText: String { return self._s[1193]! } + public var Map_ShareLiveLocation: String { return self._s[1194]! } + public var Calls_All: String { return self._s[1195]! } + public var Map_SendThisPlace: String { return self._s[1197]! } + public var Appearance_ThemeNight: String { return self._s[1199]! } + public var Conversation_HoldForAudio: String { return self._s[1200]! } + public var SettingsSearch_Synonyms_Support: String { return self._s[1203]! } + public var GroupInfo_GroupHistoryHidden: String { return self._s[1204]! } + public var SocksProxySetup_Secret: String { return self._s[1205]! } public func Activity_RemindAboutChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1201]!, self._r[1201]!, [_0]) + return formatWithArgumentRanges(self._s[1206]!, self._r[1206]!, [_0]) } - public var Channel_BanList_RestrictedTitle: String { return self._s[1203]! } - public var Conversation_Location: String { return self._s[1204]! } + public var Channel_BanList_RestrictedTitle: String { return self._s[1208]! } + public var Conversation_Location: String { return self._s[1209]! } public func AutoDownloadSettings_UpToFor(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1205]!, self._r[1205]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1210]!, self._r[1210]!, [_1, _2]) } - public var ChatSettings_AutoDownloadPhotos: String { return self._s[1207]! } - public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1208]! } - public var Notifications_PermissionsText: String { return self._s[1209]! } - public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1210]! } - public var Call_Flip: String { return self._s[1211]! } - public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1213]! } - public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1214]! } - public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1215]! } - public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1216]! } - public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1218]! } - public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1220]! } - public var Channel_TooMuchBots: String { return self._s[1222]! } - public var Passport_DeletePassportConfirmation: String { return self._s[1223]! } - public var Login_InvalidCodeError: String { return self._s[1224]! } - public var StickerPacksSettings_FeaturedPacks: String { return self._s[1225]! } + public var ChatSettings_AutoDownloadPhotos: String { return self._s[1212]! } + public var SettingsSearch_Synonyms_Privacy_Title: String { return self._s[1213]! } + public var Notifications_PermissionsText: String { return self._s[1214]! } + public var SettingsSearch_Synonyms_Data_SaveIncomingPhotos: String { return self._s[1215]! } + public var Call_Flip: String { return self._s[1216]! } + public var Channel_AdminLog_CanDeleteMessagesOfOthers: String { return self._s[1218]! } + public var SocksProxySetup_ProxyStatusConnecting: String { return self._s[1219]! } + public var Wallet_TransactionInfo_StorageFeeInfoUrl: String { return self._s[1220]! } + public var PrivacyPhoneNumberSettings_DiscoveryHeader: String { return self._s[1221]! } + public var Channel_EditAdmin_PermissionPinMessages: String { return self._s[1223]! } + public var TwoStepAuth_ReEnterPasswordDescription: String { return self._s[1225]! } + public var Channel_TooMuchBots: String { return self._s[1227]! } + public var Passport_DeletePassportConfirmation: String { return self._s[1228]! } + public var Login_InvalidCodeError: String { return self._s[1229]! } + public var StickerPacksSettings_FeaturedPacks: String { return self._s[1230]! } public func ChatList_DeleteSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1226]!, self._r[1226]!, [_0]) + return formatWithArgumentRanges(self._s[1231]!, self._r[1231]!, [_0]) } public func GroupInfo_InvitationLinkAcceptChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1227]!, self._r[1227]!, [_0]) + return formatWithArgumentRanges(self._s[1232]!, self._r[1232]!, [_0]) } - public var VoiceOver_Navigation_ProxySettings: String { return self._s[1228]! } - public var Call_CallInProgressTitle: String { return self._s[1229]! } - public var Month_ShortSeptember: String { return self._s[1230]! } - public var Watch_ChannelInfo_Title: String { return self._s[1231]! } - public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1234]! } - public var DialogList_PasscodeLockHelp: String { return self._s[1235]! } - public var Chat_MultipleTextMessagesDisabled: String { return self._s[1236]! } - public var Wallet_Receive_Title: String { return self._s[1237]! } - public var Notifications_Badge_IncludePublicGroups: String { return self._s[1238]! } - public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1239]! } - public var PhotoEditor_CropReset: String { return self._s[1240]! } - public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1242]! } - public var Channel_Management_LabelEditor: String { return self._s[1243]! } - public var Passport_Identity_LatinNameHelp: String { return self._s[1245]! } - public var PhotoEditor_HighlightsTool: String { return self._s[1246]! } - public var Wallet_Info_WalletCreated: String { return self._s[1247]! } - public var UserInfo_Title: String { return self._s[1248]! } - public var ChatList_HideAction: String { return self._s[1249]! } - public var AccessDenied_Title: String { return self._s[1250]! } - public var DialogList_SearchLabel: String { return self._s[1251]! } - public var Group_Setup_HistoryHidden: String { return self._s[1252]! } - public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1253]! } - public var State_Updating: String { return self._s[1255]! } - public var Contacts_TabTitle: String { return self._s[1256]! } - public var Notifications_Badge_CountUnreadMessages: String { return self._s[1258]! } - public var GroupInfo_GroupHistory: String { return self._s[1259]! } - public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1260]! } - public var Wallpaper_SetColor: String { return self._s[1261]! } - public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1262]! } - public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1263]! } - public var Chat_AttachmentLimitReached: String { return self._s[1264]! } - public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1265]! } - public var Contacts_NotRegisteredSection: String { return self._s[1266]! } + public var VoiceOver_Navigation_ProxySettings: String { return self._s[1233]! } + public var Call_CallInProgressTitle: String { return self._s[1234]! } + public var Month_ShortSeptember: String { return self._s[1235]! } + public var Watch_ChannelInfo_Title: String { return self._s[1236]! } + public var ChatList_DeleteSavedMessagesConfirmation: String { return self._s[1239]! } + public var DialogList_PasscodeLockHelp: String { return self._s[1240]! } + public var Chat_MultipleTextMessagesDisabled: String { return self._s[1241]! } + public var Wallet_Receive_Title: String { return self._s[1242]! } + public var Notifications_Badge_IncludePublicGroups: String { return self._s[1243]! } + public var Channel_AdminLogFilter_EventsTitle: String { return self._s[1244]! } + public var PhotoEditor_CropReset: String { return self._s[1245]! } + public var Group_Username_CreatePrivateLinkHelp: String { return self._s[1247]! } + public var Channel_Management_LabelEditor: String { return self._s[1248]! } + public var Passport_Identity_LatinNameHelp: String { return self._s[1250]! } + public var PhotoEditor_HighlightsTool: String { return self._s[1251]! } + public var Wallet_Info_WalletCreated: String { return self._s[1252]! } + public var UserInfo_Title: String { return self._s[1253]! } + public var ChatList_HideAction: String { return self._s[1254]! } + public var AccessDenied_Title: String { return self._s[1255]! } + public var DialogList_SearchLabel: String { return self._s[1256]! } + public var Group_Setup_HistoryHidden: String { return self._s[1257]! } + public var TwoStepAuth_PasswordChangeSuccess: String { return self._s[1258]! } + public var State_Updating: String { return self._s[1260]! } + public var Contacts_TabTitle: String { return self._s[1261]! } + public var Notifications_Badge_CountUnreadMessages: String { return self._s[1263]! } + public var GroupInfo_GroupHistory: String { return self._s[1264]! } + public var Conversation_UnsupportedMediaPlaceholder: String { return self._s[1265]! } + public var Wallpaper_SetColor: String { return self._s[1266]! } + public var CheckoutInfo_ShippingInfoCountry: String { return self._s[1267]! } + public var SettingsSearch_Synonyms_SavedMessages: String { return self._s[1268]! } + public var Chat_AttachmentLimitReached: String { return self._s[1269]! } + public var Passport_Identity_OneOfTypeDriversLicense: String { return self._s[1270]! } + public var Contacts_NotRegisteredSection: String { return self._s[1271]! } public func Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1267]!, self._r[1267]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1272]!, self._r[1272]!, [_1, _2, _3]) } - public var Paint_Clear: String { return self._s[1268]! } - public var StickerPacksSettings_ArchivedMasks: String { return self._s[1269]! } - public var SocksProxySetup_Connecting: String { return self._s[1270]! } - public var ExplicitContent_AlertChannel: String { return self._s[1271]! } - public var CreatePoll_AllOptionsAdded: String { return self._s[1272]! } - public var Conversation_Contact: String { return self._s[1273]! } - public var Login_CodeExpired: String { return self._s[1274]! } - public var Passport_DiscardMessageAction: String { return self._s[1275]! } - public var ChatList_Context_Unpin: String { return self._s[1276]! } - public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1277]! } + public var Paint_Clear: String { return self._s[1273]! } + public var StickerPacksSettings_ArchivedMasks: String { return self._s[1274]! } + public var SocksProxySetup_Connecting: String { return self._s[1275]! } + public var ExplicitContent_AlertChannel: String { return self._s[1276]! } + public var CreatePoll_AllOptionsAdded: String { return self._s[1277]! } + public var Conversation_Contact: String { return self._s[1278]! } + public var Login_CodeExpired: String { return self._s[1279]! } + public var Passport_DiscardMessageAction: String { return self._s[1280]! } + public var ChatList_Context_Unpin: String { return self._s[1281]! } + public var Channel_AdminLog_MessagePreviousDescription: String { return self._s[1282]! } public func VoiceOver_Chat_MusicFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1278]!, self._r[1278]!, [_0]) + return formatWithArgumentRanges(self._s[1283]!, self._r[1283]!, [_0]) } - public var Channel_AdminLog_EmptyMessageText: String { return self._s[1279]! } - public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1280]! } + public var Channel_AdminLog_EmptyMessageText: String { return self._s[1284]! } + public var SettingsSearch_Synonyms_Data_NetworkUsage: String { return self._s[1285]! } public func Group_EditAdmin_RankInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1281]!, self._r[1281]!, [_0]) + return formatWithArgumentRanges(self._s[1286]!, self._r[1286]!, [_0]) } - public var Month_ShortApril: String { return self._s[1282]! } - public var AuthSessions_CurrentSession: String { return self._s[1283]! } - public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1286]! } - public var Wallet_Navigation_Cancel: String { return self._s[1288]! } - public var WallpaperPreview_CropTopText: String { return self._s[1289]! } - public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1290]! } - public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1291]! } + public var Month_ShortApril: String { return self._s[1287]! } + public var AuthSessions_CurrentSession: String { return self._s[1288]! } + public var Chat_AttachmentMultipleFilesDisabled: String { return self._s[1291]! } + public var Wallet_Navigation_Cancel: String { return self._s[1293]! } + public var WallpaperPreview_CropTopText: String { return self._s[1294]! } + public var PrivacySettings_DeleteAccountIfAwayFor: String { return self._s[1295]! } + public var CheckoutInfo_ShippingInfoTitle: String { return self._s[1296]! } public func Conversation_ScheduleMessage_SendOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1292]!, self._r[1292]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1297]!, self._r[1297]!, [_0, _1]) } - public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1293]! } - public var Channel_Setup_TypePrivate: String { return self._s[1295]! } - public var Forward_ChannelReadOnly: String { return self._s[1298]! } - public var PhotoEditor_CurvesBlue: String { return self._s[1299]! } - public var AddContact_SharedContactException: String { return self._s[1300]! } - public var UserInfo_BotPrivacy: String { return self._s[1302]! } - public var Wallet_CreateInvoice_Title: String { return self._s[1303]! } - public var Notification_PassportValueEmail: String { return self._s[1304]! } - public var EmptyGroupInfo_Subtitle: String { return self._s[1305]! } - public var GroupPermission_NewTitle: String { return self._s[1306]! } - public var CallFeedback_ReasonDropped: String { return self._s[1307]! } - public var GroupInfo_Permissions_AddException: String { return self._s[1308]! } - public var Channel_SignMessages_Help: String { return self._s[1310]! } - public var Undo_ChatDeleted: String { return self._s[1312]! } - public var Conversation_ChatBackground: String { return self._s[1313]! } + public var Appearance_ThemePreview_Chat_2_Text: String { return self._s[1298]! } + public var Channel_Setup_TypePrivate: String { return self._s[1300]! } + public var Forward_ChannelReadOnly: String { return self._s[1303]! } + public var PhotoEditor_CurvesBlue: String { return self._s[1304]! } + public var AddContact_SharedContactException: String { return self._s[1305]! } + public var UserInfo_BotPrivacy: String { return self._s[1307]! } + public var Wallet_CreateInvoice_Title: String { return self._s[1308]! } + public var Notification_PassportValueEmail: String { return self._s[1309]! } + public var EmptyGroupInfo_Subtitle: String { return self._s[1310]! } + public var GroupPermission_NewTitle: String { return self._s[1311]! } + public var CallFeedback_ReasonDropped: String { return self._s[1312]! } + public var GroupInfo_Permissions_AddException: String { return self._s[1313]! } + public var Channel_SignMessages_Help: String { return self._s[1315]! } + public var Undo_ChatDeleted: String { return self._s[1317]! } + public var Conversation_ChatBackground: String { return self._s[1318]! } public func Wallet_WordCheck_Text(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1314]!, self._r[1314]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1319]!, self._r[1319]!, [_1, _2, _3]) } - public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1315]! } - public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1316]! } - public var Passport_Language_pt: String { return self._s[1317]! } - public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1318]! } - public var NotificationsSound_Popcorn: String { return self._s[1321]! } - public var AutoNightTheme_Disabled: String { return self._s[1322]! } - public var BlockedUsers_LeavePrefix: String { return self._s[1323]! } - public var WallpaperPreview_CustomColorTopText: String { return self._s[1324]! } - public var Contacts_PermissionsSuppressWarningText: String { return self._s[1325]! } - public var WallpaperSearch_ColorBlue: String { return self._s[1326]! } + public var ChannelMembers_WhoCanAddMembers_Admins: String { return self._s[1320]! } + public var FastTwoStepSetup_EmailPlaceholder: String { return self._s[1321]! } + public var Passport_Language_pt: String { return self._s[1322]! } + public var VoiceOver_Chat_YourVoiceMessage: String { return self._s[1323]! } + public var NotificationsSound_Popcorn: String { return self._s[1326]! } + public var AutoNightTheme_Disabled: String { return self._s[1327]! } + public var BlockedUsers_LeavePrefix: String { return self._s[1328]! } + public var WallpaperPreview_CustomColorTopText: String { return self._s[1329]! } + public var Contacts_PermissionsSuppressWarningText: String { return self._s[1330]! } + public var WallpaperSearch_ColorBlue: String { return self._s[1331]! } public func CancelResetAccount_TextSMS(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1327]!, self._r[1327]!, [_0]) + return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, [_0]) } - public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1328]! } - public var SocksProxySetup_UseForCalls: String { return self._s[1329]! } - public var Passport_DeleteDocumentConfirmation: String { return self._s[1331]! } + public var CheckoutInfo_ErrorNameInvalid: String { return self._s[1333]! } + public var SocksProxySetup_UseForCalls: String { return self._s[1334]! } + public var Passport_DeleteDocumentConfirmation: String { return self._s[1336]! } public func Conversation_Megabytes(_ _0: Float) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1332]!, self._r[1332]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[1337]!, self._r[1337]!, ["\(_0)"]) } - public var SocksProxySetup_Hostname: String { return self._s[1335]! } - public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1336]! } - public var Compose_NewEncryptedChat: String { return self._s[1337]! } - public var Login_CodeFloodError: String { return self._s[1338]! } - public var Calls_TabTitle: String { return self._s[1339]! } - public var Privacy_ProfilePhoto: String { return self._s[1340]! } - public var Passport_Language_he: String { return self._s[1341]! } + public var SocksProxySetup_Hostname: String { return self._s[1340]! } + public var ChatSettings_AutoDownloadSettings_OffForAll: String { return self._s[1341]! } + public var Compose_NewEncryptedChat: String { return self._s[1342]! } + public var Login_CodeFloodError: String { return self._s[1343]! } + public var Calls_TabTitle: String { return self._s[1344]! } + public var Privacy_ProfilePhoto: String { return self._s[1345]! } + public var Passport_Language_he: String { return self._s[1346]! } public func Conversation_SetReminder_RemindToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1342]!, self._r[1342]!, [_0]) + return formatWithArgumentRanges(self._s[1347]!, self._r[1347]!, [_0]) } - public var GroupPermission_Title: String { return self._s[1343]! } + public var GroupPermission_Title: String { return self._s[1348]! } public func Channel_AdminLog_MessageGroupPreHistoryHidden(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1344]!, self._r[1344]!, [_0]) + return formatWithArgumentRanges(self._s[1349]!, self._r[1349]!, [_0]) } - public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1345]! } - public var GroupPermission_NoChangeInfo: String { return self._s[1346]! } - public var ChatList_DeleteForCurrentUser: String { return self._s[1347]! } - public var Tour_Text1: String { return self._s[1348]! } - public var Channel_EditAdmin_TransferOwnership: String { return self._s[1349]! } - public var Month_ShortFebruary: String { return self._s[1350]! } - public var TwoStepAuth_EmailSkip: String { return self._s[1351]! } + public var Wallet_TransactionInfo_SenderHeader: String { return self._s[1350]! } + public var GroupPermission_NoChangeInfo: String { return self._s[1351]! } + public var ChatList_DeleteForCurrentUser: String { return self._s[1352]! } + public var Tour_Text1: String { return self._s[1353]! } + public var Channel_EditAdmin_TransferOwnership: String { return self._s[1354]! } + public var Month_ShortFebruary: String { return self._s[1355]! } + public var TwoStepAuth_EmailSkip: String { return self._s[1356]! } public func Wallet_Time_PreciseDate_m4(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1352]!, self._r[1352]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1357]!, self._r[1357]!, [_1, _2, _3]) } - public var NotificationsSound_Glass: String { return self._s[1353]! } - public var Appearance_ThemeNightBlue: String { return self._s[1354]! } - public var CheckoutInfo_Pay: String { return self._s[1355]! } - public var Invite_LargeRecipientsCountWarning: String { return self._s[1357]! } - public var Call_CallAgain: String { return self._s[1359]! } - public var AttachmentMenu_SendAsFile: String { return self._s[1360]! } - public var AccessDenied_MicrophoneRestricted: String { return self._s[1361]! } - public var Passport_InvalidPasswordError: String { return self._s[1362]! } - public var Watch_Message_Game: String { return self._s[1363]! } - public var Stickers_Install: String { return self._s[1364]! } - public var VoiceOver_Chat_Message: String { return self._s[1365]! } - public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1366]! } - public var Passport_Identity_ResidenceCountry: String { return self._s[1368]! } - public var Notifications_GroupNotificationsHelp: String { return self._s[1369]! } - public var AuthSessions_OtherSessions: String { return self._s[1370]! } - public var Channel_Username_Help: String { return self._s[1371]! } - public var Camera_Title: String { return self._s[1372]! } - public var IntentsSettings_Title: String { return self._s[1373]! } - public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1375]! } - public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1376]! } - public var Channel_AdminLog_SendPolls: String { return self._s[1377]! } - public var Channel_AdminLog_TitleAllEvents: String { return self._s[1378]! } - public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1379]! } - public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1380]! } - public var ScheduledMessages_DeleteMany: String { return self._s[1381]! } - public var Conversation_RestrictedStickers: String { return self._s[1382]! } - public var Notifications_ExceptionsResetToDefaults: String { return self._s[1384]! } - public var UserInfo_TelegramCall: String { return self._s[1386]! } - public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1387]! } - public var CreatePoll_OptionsHeader: String { return self._s[1388]! } - public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1389]! } - public var ArchivedChats_IntroTitle1: String { return self._s[1390]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1391]! } - public var Theme_Colors_Proceed: String { return self._s[1392]! } - public var Passport_Identity_EditPersonalDetails: String { return self._s[1393]! } + public var NotificationsSound_Glass: String { return self._s[1358]! } + public var Appearance_ThemeNightBlue: String { return self._s[1359]! } + public var CheckoutInfo_Pay: String { return self._s[1360]! } + public var Invite_LargeRecipientsCountWarning: String { return self._s[1362]! } + public var Call_CallAgain: String { return self._s[1364]! } + public var AttachmentMenu_SendAsFile: String { return self._s[1365]! } + public var AccessDenied_MicrophoneRestricted: String { return self._s[1366]! } + public var Passport_InvalidPasswordError: String { return self._s[1367]! } + public var Watch_Message_Game: String { return self._s[1368]! } + public var Stickers_Install: String { return self._s[1369]! } + public var VoiceOver_Chat_Message: String { return self._s[1370]! } + public var PrivacyLastSeenSettings_NeverShareWith: String { return self._s[1371]! } + public var Passport_Identity_ResidenceCountry: String { return self._s[1373]! } + public var Notifications_GroupNotificationsHelp: String { return self._s[1374]! } + public var AuthSessions_OtherSessions: String { return self._s[1375]! } + public var Channel_Username_Help: String { return self._s[1376]! } + public var Camera_Title: String { return self._s[1377]! } + public var IntentsSettings_Title: String { return self._s[1378]! } + public var GroupInfo_SetGroupPhotoDelete: String { return self._s[1380]! } + public var Privacy_ProfilePhoto_NeverShareWith_Title: String { return self._s[1381]! } + public var Channel_AdminLog_SendPolls: String { return self._s[1382]! } + public var Channel_AdminLog_TitleAllEvents: String { return self._s[1383]! } + public var Channel_EditAdmin_PermissionInviteMembers: String { return self._s[1384]! } + public var Contacts_MemberSearchSectionTitleGroup: String { return self._s[1385]! } + public var ScheduledMessages_DeleteMany: String { return self._s[1386]! } + public var Conversation_RestrictedStickers: String { return self._s[1387]! } + public var Notifications_ExceptionsResetToDefaults: String { return self._s[1389]! } + public var UserInfo_TelegramCall: String { return self._s[1391]! } + public var TwoStepAuth_SetupResendEmailCode: String { return self._s[1392]! } + public var CreatePoll_OptionsHeader: String { return self._s[1393]! } + public var SettingsSearch_Synonyms_Data_CallsUseLessData: String { return self._s[1394]! } + public var ArchivedChats_IntroTitle1: String { return self._s[1395]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Title: String { return self._s[1396]! } + public var Theme_Colors_Proceed: String { return self._s[1397]! } + public var Passport_Identity_EditPersonalDetails: String { return self._s[1398]! } public func Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1394]!, self._r[1394]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1399]!, self._r[1399]!, [_1, _2, _3]) } - public var Wallet_Month_GenAugust: String { return self._s[1395]! } - public var Settings_SaveEditedPhotos: String { return self._s[1396]! } - public var TwoStepAuth_ConfirmationTitle: String { return self._s[1397]! } - public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1398]! } - public var Conversation_MessageDialogRetry: String { return self._s[1399]! } - public var ChatList_Context_MarkAsUnread: String { return self._s[1400]! } - public var MessagePoll_SubmitVote: String { return self._s[1401]! } - public var Conversation_DiscardVoiceMessageAction: String { return self._s[1402]! } - public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1403]! } - public var Group_Setup_TypeHeader: String { return self._s[1404]! } - public var Paint_RecentStickers: String { return self._s[1405]! } - public var PhotoEditor_GrainTool: String { return self._s[1406]! } - public var CheckoutInfo_ShippingInfoState: String { return self._s[1407]! } - public var EmptyGroupInfo_Line4: String { return self._s[1408]! } - public var Watch_AuthRequired: String { return self._s[1410]! } + public var Wallet_Month_GenAugust: String { return self._s[1400]! } + public var Settings_SaveEditedPhotos: String { return self._s[1401]! } + public var TwoStepAuth_ConfirmationTitle: String { return self._s[1402]! } + public var Privacy_GroupsAndChannels_NeverAllow_Title: String { return self._s[1403]! } + public var Conversation_MessageDialogRetry: String { return self._s[1404]! } + public var ChatList_Context_MarkAsUnread: String { return self._s[1405]! } + public var MessagePoll_SubmitVote: String { return self._s[1406]! } + public var Conversation_DiscardVoiceMessageAction: String { return self._s[1407]! } + public var Permissions_PeopleNearbyTitle_v0: String { return self._s[1408]! } + public var Group_Setup_TypeHeader: String { return self._s[1409]! } + public var Paint_RecentStickers: String { return self._s[1410]! } + public var PhotoEditor_GrainTool: String { return self._s[1411]! } + public var CheckoutInfo_ShippingInfoState: String { return self._s[1412]! } + public var EmptyGroupInfo_Line4: String { return self._s[1413]! } + public var Watch_AuthRequired: String { return self._s[1415]! } public func Passport_Email_UseTelegramEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1411]!, self._r[1411]!, [_0]) + return formatWithArgumentRanges(self._s[1416]!, self._r[1416]!, [_0]) } - public var Conversation_EncryptedDescriptionTitle: String { return self._s[1412]! } - public var ChannelIntro_Text: String { return self._s[1413]! } - public var DialogList_DeleteBotConfirmation: String { return self._s[1414]! } - public var GroupPermission_NoSendMedia: String { return self._s[1415]! } - public var Calls_AddTab: String { return self._s[1416]! } - public var Message_ReplyActionButtonShowReceipt: String { return self._s[1417]! } - public var Channel_AdminLog_EmptyFilterText: String { return self._s[1418]! } - public var Conversation_WalletRequiredSetup: String { return self._s[1419]! } - public var Notification_MessageLifetime1d: String { return self._s[1420]! } - public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1421]! } - public var Channel_BanUser_PermissionsHeader: String { return self._s[1422]! } - public var Passport_Identity_GenderFemale: String { return self._s[1423]! } - public var BlockedUsers_BlockTitle: String { return self._s[1424]! } + public var Conversation_EncryptedDescriptionTitle: String { return self._s[1417]! } + public var ChannelIntro_Text: String { return self._s[1418]! } + public var DialogList_DeleteBotConfirmation: String { return self._s[1419]! } + public var GroupPermission_NoSendMedia: String { return self._s[1420]! } + public var Calls_AddTab: String { return self._s[1421]! } + public var Message_ReplyActionButtonShowReceipt: String { return self._s[1422]! } + public var Channel_AdminLog_EmptyFilterText: String { return self._s[1423]! } + public var Conversation_WalletRequiredSetup: String { return self._s[1424]! } + public var Notification_MessageLifetime1d: String { return self._s[1425]! } + public var Notifications_ChannelNotificationsExceptionsHelp: String { return self._s[1426]! } + public var Channel_BanUser_PermissionsHeader: String { return self._s[1427]! } + public var Passport_Identity_GenderFemale: String { return self._s[1428]! } + public var BlockedUsers_BlockTitle: String { return self._s[1429]! } public func PUSH_CHANNEL_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1425]!, self._r[1425]!, [_1]) + return formatWithArgumentRanges(self._s[1430]!, self._r[1430]!, [_1]) } - public var Weekday_Yesterday: String { return self._s[1426]! } - public var WallpaperSearch_ColorBlack: String { return self._s[1427]! } - public var Settings_Context_Logout: String { return self._s[1428]! } - public var Wallet_Info_UnknownTransaction: String { return self._s[1429]! } - public var ChatList_ArchiveAction: String { return self._s[1430]! } - public var AutoNightTheme_Scheduled: String { return self._s[1431]! } - public var TwoFactorSetup_Email_SkipAction: String { return self._s[1432]! } - public var Settings_Devices: String { return self._s[1433]! } - public var ContactInfo_Note: String { return self._s[1434]! } + public var Weekday_Yesterday: String { return self._s[1431]! } + public var WallpaperSearch_ColorBlack: String { return self._s[1432]! } + public var Settings_Context_Logout: String { return self._s[1433]! } + public var Wallet_Info_UnknownTransaction: String { return self._s[1434]! } + public var ChatList_ArchiveAction: String { return self._s[1435]! } + public var AutoNightTheme_Scheduled: String { return self._s[1436]! } + public var TwoFactorSetup_Email_SkipAction: String { return self._s[1437]! } + public var Settings_Devices: String { return self._s[1438]! } + public var ContactInfo_Note: String { return self._s[1439]! } public func Login_PhoneGenericEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String, _ _6: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1435]!, self._r[1435]!, [_1, _2, _3, _4, _5, _6]) + return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2, _3, _4, _5, _6]) } - public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1436]! } - public var Wallet_Receive_CreateInvoice: String { return self._s[1437]! } - public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1438]! } - public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1439]! } + public var EditTheme_ThemeTemplateAlertTitle: String { return self._s[1441]! } + public var Wallet_Receive_CreateInvoice: String { return self._s[1442]! } + public var PrivacyPolicy_DeclineDeleteNow: String { return self._s[1443]! } + public var Theme_Colors_ColorWallpaperWarningProceed: String { return self._s[1444]! } public func PUSH_CHAT_JOINED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1440]!, self._r[1440]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1445]!, self._r[1445]!, [_1, _2]) } - public var CreatePoll_Create: String { return self._s[1441]! } - public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1442]! } + public var CreatePoll_Create: String { return self._s[1446]! } + public var Channel_Members_AddBannedErrorAdmin: String { return self._s[1447]! } public func Notification_CallFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1443]!, self._r[1443]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1, _2]) } - public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1444]! } - public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1445]! } - public var Notifications_InAppNotificationsSounds: String { return self._s[1447]! } + public var ScheduledMessages_ClearAllConfirmation: String { return self._s[1449]! } + public var Checkout_ErrorProviderAccountInvalid: String { return self._s[1450]! } + public var Notifications_InAppNotificationsSounds: String { return self._s[1452]! } public func PUSH_PINNED_GAME_SCORE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1448]!, self._r[1448]!, [_1]) + return formatWithArgumentRanges(self._s[1453]!, self._r[1453]!, [_1]) } - public var Preview_OpenInInstagram: String { return self._s[1449]! } - public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1450]! } + public var Preview_OpenInInstagram: String { return self._s[1454]! } + public var Notification_MessageLifetimeRemovedOutgoing: String { return self._s[1455]! } public func PUSH_CHAT_ADD_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1451]!, self._r[1451]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1456]!, self._r[1456]!, [_1, _2, _3]) } public func Passport_PrivacyPolicy(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1452]!, self._r[1452]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1457]!, self._r[1457]!, [_1, _2]) } - public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1453]! } - public var ArchivedChats_IntroText3: String { return self._s[1454]! } - public var ChatList_UndoArchiveHiddenText: String { return self._s[1455]! } - public var NetworkUsageSettings_TotalSection: String { return self._s[1456]! } - public var Wallet_Month_GenSeptember: String { return self._s[1457]! } - public var Channel_Setup_TypePrivateHelp: String { return self._s[1458]! } + public var Channel_AdminLog_InfoPanelAlertTitle: String { return self._s[1458]! } + public var ArchivedChats_IntroText3: String { return self._s[1459]! } + public var ChatList_UndoArchiveHiddenText: String { return self._s[1460]! } + public var NetworkUsageSettings_TotalSection: String { return self._s[1461]! } + public var Wallet_Month_GenSeptember: String { return self._s[1462]! } + public var Channel_Setup_TypePrivateHelp: String { return self._s[1463]! } public func PUSH_CHAT_MESSAGE_POLL(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1459]!, self._r[1459]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1464]!, self._r[1464]!, [_1, _2, _3]) } - public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1461]! } - public var FastTwoStepSetup_HintSection: String { return self._s[1462]! } - public var Wallpaper_PhotoLibrary: String { return self._s[1463]! } - public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1464]! } - public var Gif_NoGifsFound: String { return self._s[1465]! } - public var Watch_LastSeen_WithinAMonth: String { return self._s[1466]! } - public var VoiceOver_MessageContextDelete: String { return self._s[1467]! } - public var EditTheme_Preview: String { return self._s[1468]! } + public var Privacy_GroupsAndChannels_NeverAllow_Placeholder: String { return self._s[1466]! } + public var FastTwoStepSetup_HintSection: String { return self._s[1467]! } + public var Wallpaper_PhotoLibrary: String { return self._s[1468]! } + public var TwoStepAuth_SetupResendEmailCodeAlert: String { return self._s[1469]! } + public var Gif_NoGifsFound: String { return self._s[1470]! } + public var Watch_LastSeen_WithinAMonth: String { return self._s[1471]! } + public var VoiceOver_MessageContextDelete: String { return self._s[1472]! } + public var EditTheme_Preview: String { return self._s[1473]! } public func ClearCache_StorageTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1469]!, self._r[1469]!, [_0]) + return formatWithArgumentRanges(self._s[1474]!, self._r[1474]!, [_0]) } - public var GroupInfo_ActionPromote: String { return self._s[1470]! } - public var PasscodeSettings_SimplePasscode: String { return self._s[1471]! } - public var GroupInfo_Permissions_Title: String { return self._s[1472]! } - public var Permissions_ContactsText_v0: String { return self._s[1473]! } - public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1474]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1475]! } - public var PrivacySettings_DataSettingsHelp: String { return self._s[1478]! } - public var Passport_FieldEmailHelp: String { return self._s[1479]! } + public var GroupInfo_ActionPromote: String { return self._s[1475]! } + public var PasscodeSettings_SimplePasscode: String { return self._s[1476]! } + public var GroupInfo_Permissions_Title: String { return self._s[1477]! } + public var Permissions_ContactsText_v0: String { return self._s[1478]! } + public var PrivacyPhoneNumberSettings_CustomDisabledHelp: String { return self._s[1479]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups: String { return self._s[1480]! } + public var PrivacySettings_DataSettingsHelp: String { return self._s[1483]! } + public var Passport_FieldEmailHelp: String { return self._s[1484]! } public func Activity_RemindAboutUser(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1480]!, self._r[1480]!, [_0]) + return formatWithArgumentRanges(self._s[1485]!, self._r[1485]!, [_0]) } - public var Passport_Identity_GenderPlaceholder: String { return self._s[1481]! } - public var Weekday_ShortSaturday: String { return self._s[1482]! } - public var ContactInfo_PhoneLabelMain: String { return self._s[1483]! } - public var Watch_Conversation_UserInfo: String { return self._s[1484]! } - public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1485]! } - public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1486]! } - public var PrivacyLastSeenSettings_Title: String { return self._s[1487]! } - public var Conversation_ShareBotLocationConfirmation: String { return self._s[1488]! } - public var PhotoEditor_VignetteTool: String { return self._s[1489]! } - public var Passport_Address_Street1Placeholder: String { return self._s[1490]! } - public var Passport_Language_et: String { return self._s[1491]! } - public var AppUpgrade_Running: String { return self._s[1492]! } - public var Channel_DiscussionGroup_Info: String { return self._s[1494]! } - public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1495]! } - public var Passport_Language_bg: String { return self._s[1496]! } - public var Stickers_NoStickersFound: String { return self._s[1498]! } + public var Passport_Identity_GenderPlaceholder: String { return self._s[1486]! } + public var Weekday_ShortSaturday: String { return self._s[1487]! } + public var ContactInfo_PhoneLabelMain: String { return self._s[1488]! } + public var Watch_Conversation_UserInfo: String { return self._s[1489]! } + public var CheckoutInfo_ShippingInfoCityPlaceholder: String { return self._s[1490]! } + public var GroupPermission_PermissionDisabledByDefault: String { return self._s[1491]! } + public var PrivacyLastSeenSettings_Title: String { return self._s[1492]! } + public var Conversation_ShareBotLocationConfirmation: String { return self._s[1493]! } + public var PhotoEditor_VignetteTool: String { return self._s[1494]! } + public var Passport_Address_Street1Placeholder: String { return self._s[1495]! } + public var Passport_Language_et: String { return self._s[1496]! } + public var AppUpgrade_Running: String { return self._s[1497]! } + public var Channel_DiscussionGroup_Info: String { return self._s[1499]! } + public var EditTheme_Create_Preview_IncomingReplyName: String { return self._s[1500]! } + public var Passport_Language_bg: String { return self._s[1501]! } + public var Stickers_NoStickersFound: String { return self._s[1503]! } public func PUSH_CHANNEL_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1500]!, self._r[1500]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1505]!, self._r[1505]!, [_1, _2]) } public func VoiceOver_Chat_ContactFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1501]!, self._r[1501]!, [_0]) + return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0]) } - public var Wallet_Month_GenJuly: String { return self._s[1502]! } - public var Wallet_Receive_AddressHeader: String { return self._s[1503]! } - public var Wallet_Send_AmountText: String { return self._s[1504]! } - public var Settings_About: String { return self._s[1505]! } + public var Wallet_Month_GenJuly: String { return self._s[1507]! } + public var Wallet_Receive_AddressHeader: String { return self._s[1508]! } + public var Wallet_Send_AmountText: String { return self._s[1509]! } + public var Settings_About: String { return self._s[1510]! } public func Channel_AdminLog_MessageRestricted(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1506]!, self._r[1506]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0, _1, _2]) } - public var ChatList_Context_MarkAsRead: String { return self._s[1508]! } - public var KeyCommand_NewMessage: String { return self._s[1509]! } - public var Group_ErrorAddBlocked: String { return self._s[1510]! } + public var ChatList_Context_MarkAsRead: String { return self._s[1513]! } + public var KeyCommand_NewMessage: String { return self._s[1514]! } + public var Group_ErrorAddBlocked: String { return self._s[1515]! } public func Message_PaymentSent(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1511]!, self._r[1511]!, [_0]) - } - public var Map_LocationTitle: String { return self._s[1512]! } - public var ReportGroupLocation_Title: String { return self._s[1513]! } - public var CallSettings_UseLessDataLongDescription: String { return self._s[1514]! } - public var Cache_ClearProgress: String { return self._s[1515]! } - public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1516]!, self._r[1516]!, [_0]) } - public var GroupRemoved_AddToGroup: String { return self._s[1517]! } - public var Passport_UpdateRequiredError: String { return self._s[1518]! } - public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1519]! } + public var Map_LocationTitle: String { return self._s[1517]! } + public var ReportGroupLocation_Title: String { return self._s[1518]! } + public var CallSettings_UseLessDataLongDescription: String { return self._s[1519]! } + public var Cache_ClearProgress: String { return self._s[1520]! } + public func Channel_Management_ErrorNotMember(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1521]!, self._r[1521]!, [_0]) + } + public var GroupRemoved_AddToGroup: String { return self._s[1522]! } + public var Passport_UpdateRequiredError: String { return self._s[1523]! } + public var Wallet_SecureStorageNotAvailable_Text: String { return self._s[1524]! } public func PUSH_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1520]!, self._r[1520]!, [_1]) + return formatWithArgumentRanges(self._s[1525]!, self._r[1525]!, [_1]) } - public var Notifications_PermissionsSuppressWarningText: String { return self._s[1522]! } - public var Passport_Identity_MainPageHelp: String { return self._s[1523]! } - public var Conversation_StatusKickedFromGroup: String { return self._s[1524]! } - public var Passport_Language_ka: String { return self._s[1525]! } + public var Notifications_PermissionsSuppressWarningText: String { return self._s[1527]! } + public var Passport_Identity_MainPageHelp: String { return self._s[1528]! } + public var Conversation_StatusKickedFromGroup: String { return self._s[1529]! } + public var Passport_Language_ka: String { return self._s[1530]! } public func Wallet_Time_PreciseDate_m12(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1526]!, self._r[1526]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1531]!, self._r[1531]!, [_1, _2, _3]) } - public var Call_Decline: String { return self._s[1527]! } - public var SocksProxySetup_ProxyEnabled: String { return self._s[1528]! } - public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1531]! } + public var Call_Decline: String { return self._s[1532]! } + public var SocksProxySetup_ProxyEnabled: String { return self._s[1533]! } + public var TwoFactorSetup_Email_SkipConfirmationText: String { return self._s[1536]! } public func AuthCode_Alert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1532]!, self._r[1532]!, [_0]) + return formatWithArgumentRanges(self._s[1537]!, self._r[1537]!, [_0]) } - public var CallFeedback_Send: String { return self._s[1533]! } - public var EditTheme_EditTitle: String { return self._s[1534]! } + public var CallFeedback_Send: String { return self._s[1538]! } + public var EditTheme_EditTitle: String { return self._s[1539]! } public func Channel_AdminLog_MessagePromotedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1535]!, self._r[1535]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1540]!, self._r[1540]!, [_1, _2]) } - public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1536]! } + public var Passport_Phone_UseTelegramNumberHelp: String { return self._s[1541]! } public func Wallet_Updated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1538]!, self._r[1538]!, [_0]) + return formatWithArgumentRanges(self._s[1543]!, self._r[1543]!, [_0]) } - public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1539]! } - public var Passport_DeletePassport: String { return self._s[1540]! } - public var Appearance_AppIconFilled: String { return self._s[1541]! } - public var Privacy_Calls_P2PAlways: String { return self._s[1542]! } - public var Month_ShortDecember: String { return self._s[1543]! } - public var Channel_AdminLog_CanEditMessages: String { return self._s[1545]! } + public var SettingsSearch_Synonyms_Data_Title: String { return self._s[1544]! } + public var Passport_DeletePassport: String { return self._s[1545]! } + public var Appearance_AppIconFilled: String { return self._s[1546]! } + public var Privacy_Calls_P2PAlways: String { return self._s[1547]! } + public var Month_ShortDecember: String { return self._s[1548]! } + public var Channel_AdminLog_CanEditMessages: String { return self._s[1550]! } public func Contacts_AccessDeniedHelpLandscape(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1546]!, self._r[1546]!, [_0]) + return formatWithArgumentRanges(self._s[1551]!, self._r[1551]!, [_0]) } - public var Channel_Stickers_Searching: String { return self._s[1547]! } - public var Conversation_EncryptedDescription1: String { return self._s[1548]! } - public var Conversation_EncryptedDescription2: String { return self._s[1549]! } - public var PasscodeSettings_PasscodeOptions: String { return self._s[1550]! } - public var Conversation_EncryptedDescription3: String { return self._s[1552]! } - public var PhotoEditor_SharpenTool: String { return self._s[1553]! } - public var Wallet_Configuration_Title: String { return self._s[1554]! } + public var Channel_Stickers_Searching: String { return self._s[1552]! } + public var Conversation_EncryptedDescription1: String { return self._s[1553]! } + public var Conversation_EncryptedDescription2: String { return self._s[1554]! } + public var PasscodeSettings_PasscodeOptions: String { return self._s[1555]! } + public var Conversation_EncryptedDescription3: String { return self._s[1557]! } + public var PhotoEditor_SharpenTool: String { return self._s[1558]! } + public var Wallet_Configuration_Title: String { return self._s[1559]! } public func Conversation_AddNameToContacts(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1555]!, self._r[1555]!, [_0]) + return formatWithArgumentRanges(self._s[1560]!, self._r[1560]!, [_0]) } - public var Conversation_EncryptedDescription4: String { return self._s[1557]! } - public var Channel_Members_AddMembers: String { return self._s[1558]! } - public var Wallpaper_Search: String { return self._s[1559]! } - public var Weekday_Friday: String { return self._s[1561]! } - public var Privacy_ContactsSync: String { return self._s[1562]! } - public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1563]! } - public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1564]! } + public var Conversation_EncryptedDescription4: String { return self._s[1562]! } + public var Channel_Members_AddMembers: String { return self._s[1563]! } + public var Wallpaper_Search: String { return self._s[1564]! } + public var Weekday_Friday: String { return self._s[1566]! } + public var Privacy_ContactsSync: String { return self._s[1567]! } + public var SettingsSearch_Synonyms_Privacy_Data_ContactsReset: String { return self._s[1568]! } + public var ApplyLanguage_ChangeLanguageAction: String { return self._s[1569]! } public func Channel_Management_RestrictedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1565]!, self._r[1565]!, [_0]) - } - public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1566]! } - public var GroupInfo_Permissions_Removed: String { return self._s[1567]! } - public var ScheduledMessages_ScheduledOnline: String { return self._s[1568]! } - public var Passport_Identity_GenderMale: String { return self._s[1569]! } - public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[1570]!, self._r[1570]!, [_0]) } - public var Notifications_PermissionsKeepDisabled: String { return self._s[1571]! } - public var Conversation_JumpToDate: String { return self._s[1572]! } - public var Contacts_GlobalSearch: String { return self._s[1573]! } - public var AutoDownloadSettings_ResetHelp: String { return self._s[1574]! } - public var SettingsSearch_Synonyms_FAQ: String { return self._s[1575]! } - public var Profile_MessageLifetime1d: String { return self._s[1576]! } + public var Wallet_Configuration_BlockchainIdHeader: String { return self._s[1571]! } + public var GroupInfo_Permissions_Removed: String { return self._s[1572]! } + public var ScheduledMessages_ScheduledOnline: String { return self._s[1573]! } + public var Passport_Identity_GenderMale: String { return self._s[1574]! } + public func Call_StatusBar(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[1575]!, self._r[1575]!, [_0]) + } + public var Notifications_PermissionsKeepDisabled: String { return self._s[1576]! } + public var Conversation_JumpToDate: String { return self._s[1577]! } + public var Contacts_GlobalSearch: String { return self._s[1578]! } + public var AutoDownloadSettings_ResetHelp: String { return self._s[1579]! } + public var SettingsSearch_Synonyms_FAQ: String { return self._s[1580]! } + public var Profile_MessageLifetime1d: String { return self._s[1581]! } public func MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1577]!, self._r[1577]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1582]!, self._r[1582]!, [_1, _2]) } - public var StickerPack_BuiltinPackName: String { return self._s[1580]! } + public var StickerPack_BuiltinPackName: String { return self._s[1585]! } public func PUSH_CHAT_MESSAGE_AUDIO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1581]!, self._r[1581]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1586]!, self._r[1586]!, [_1, _2]) } - public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1582]! } - public var Passport_InfoTitle: String { return self._s[1584]! } - public var Notifications_PermissionsUnreachableText: String { return self._s[1585]! } + public var VoiceOver_Chat_RecordModeVoiceMessageInfo: String { return self._s[1587]! } + public var Passport_InfoTitle: String { return self._s[1589]! } + public var Notifications_PermissionsUnreachableText: String { return self._s[1590]! } public func NetworkUsageSettings_CellularUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1589]!, self._r[1589]!, [_0]) + return formatWithArgumentRanges(self._s[1594]!, self._r[1594]!, [_0]) } public func PUSH_CHAT_MESSAGE_GEO(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1590]!, self._r[1590]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1595]!, self._r[1595]!, [_1, _2]) } - public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1591]! } - public var Profile_BotInfo: String { return self._s[1592]! } - public var Watch_Compose_CreateMessage: String { return self._s[1593]! } - public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1594]! } - public var Month_ShortNovember: String { return self._s[1595]! } - public var Conversation_ScamWarning: String { return self._s[1596]! } - public var Wallpaper_SetCustomBackground: String { return self._s[1597]! } - public var Appearance_TextSize_Title: String { return self._s[1598]! } - public var Passport_Identity_TranslationsHelp: String { return self._s[1599]! } - public var NotificationsSound_Chime: String { return self._s[1600]! } - public var Passport_Language_ko: String { return self._s[1602]! } - public var InviteText_URL: String { return self._s[1603]! } - public var TextFormat_Monospace: String { return self._s[1604]! } + public var Passport_Address_TypePassportRegistrationUploadScan: String { return self._s[1596]! } + public var Profile_BotInfo: String { return self._s[1597]! } + public var Watch_Compose_CreateMessage: String { return self._s[1598]! } + public var AutoDownloadSettings_VoiceMessagesInfo: String { return self._s[1599]! } + public var Month_ShortNovember: String { return self._s[1600]! } + public var Conversation_ScamWarning: String { return self._s[1601]! } + public var Wallpaper_SetCustomBackground: String { return self._s[1602]! } + public var Appearance_TextSize_Title: String { return self._s[1603]! } + public var Passport_Identity_TranslationsHelp: String { return self._s[1604]! } + public var NotificationsSound_Chime: String { return self._s[1605]! } + public var Passport_Language_ko: String { return self._s[1607]! } + public var InviteText_URL: String { return self._s[1608]! } + public var TextFormat_Monospace: String { return self._s[1609]! } public func Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1605]!, self._r[1605]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1610]!, self._r[1610]!, [_1, _2, _3]) } - public var EditTheme_Edit_BottomInfo: String { return self._s[1606]! } + public var EditTheme_Edit_BottomInfo: String { return self._s[1611]! } public func Login_WillSendSms(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1607]!, self._r[1607]!, [_0]) + return formatWithArgumentRanges(self._s[1612]!, self._r[1612]!, [_0]) } public func Watch_Time_ShortWeekdayAt(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1608]!, self._r[1608]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1613]!, self._r[1613]!, [_1, _2]) } - public var Wallet_Words_Title: String { return self._s[1609]! } - public var Wallet_Month_ShortMay: String { return self._s[1610]! } - public var EditTheme_CreateTitle: String { return self._s[1612]! } - public var Passport_InfoLearnMore: String { return self._s[1613]! } - public var TwoStepAuth_EmailPlaceholder: String { return self._s[1614]! } - public var Passport_Identity_AddIdentityCard: String { return self._s[1615]! } - public var Your_card_has_expired: String { return self._s[1616]! } - public var StickerPacksSettings_StickerPacksSection: String { return self._s[1617]! } - public var GroupInfo_InviteLink_Help: String { return self._s[1618]! } - public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1622]! } - public var Conversation_Report: String { return self._s[1624]! } - public var Notifications_MessageNotificationsSound: String { return self._s[1625]! } - public var Notification_MessageLifetime1m: String { return self._s[1626]! } - public var Privacy_ContactsTitle: String { return self._s[1627]! } - public var Conversation_ShareMyContactInfo: String { return self._s[1628]! } - public var Wallet_WordCheck_Title: String { return self._s[1629]! } - public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1630]! } - public var Channel_Members_Title: String { return self._s[1631]! } - public var Map_OpenInWaze: String { return self._s[1632]! } - public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1633]! } - public var Login_PhoneBannedError: String { return self._s[1634]! } + public var Wallet_Words_Title: String { return self._s[1614]! } + public var Wallet_Month_ShortMay: String { return self._s[1615]! } + public var EditTheme_CreateTitle: String { return self._s[1617]! } + public var Passport_InfoLearnMore: String { return self._s[1618]! } + public var TwoStepAuth_EmailPlaceholder: String { return self._s[1619]! } + public var Passport_Identity_AddIdentityCard: String { return self._s[1620]! } + public var Your_card_has_expired: String { return self._s[1621]! } + public var StickerPacksSettings_StickerPacksSection: String { return self._s[1622]! } + public var GroupInfo_InviteLink_Help: String { return self._s[1623]! } + public var TwoFactorSetup_EmailVerification_ResendAction: String { return self._s[1627]! } + public var Conversation_Report: String { return self._s[1629]! } + public var Notifications_MessageNotificationsSound: String { return self._s[1630]! } + public var Notification_MessageLifetime1m: String { return self._s[1631]! } + public var Privacy_ContactsTitle: String { return self._s[1632]! } + public var Conversation_ShareMyContactInfo: String { return self._s[1633]! } + public var Wallet_WordCheck_Title: String { return self._s[1634]! } + public var ChannelMembers_WhoCanAddMembersAdminsHelp: String { return self._s[1635]! } + public var Channel_Members_Title: String { return self._s[1636]! } + public var Map_OpenInWaze: String { return self._s[1637]! } + public var Appearance_RemoveThemeColorConfirmation: String { return self._s[1638]! } + public var Login_PhoneBannedError: String { return self._s[1639]! } public func LiveLocationUpdated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1635]!, self._r[1635]!, [_0]) + return formatWithArgumentRanges(self._s[1640]!, self._r[1640]!, [_0]) } - public var IntentsSettings_MainAccount: String { return self._s[1636]! } - public var Group_Management_AddModeratorHelp: String { return self._s[1637]! } - public var AutoDownloadSettings_WifiTitle: String { return self._s[1638]! } - public var Common_OK: String { return self._s[1639]! } - public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1640]! } - public var Wallet_Words_NotDoneResponse: String { return self._s[1641]! } - public var Cache_Music: String { return self._s[1642]! } - public var Wallet_Configuration_SourceURL: String { return self._s[1643]! } - public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1644]! } - public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1646]! } - public var TwoStepAuth_HintPlaceholder: String { return self._s[1647]! } + public var IntentsSettings_MainAccount: String { return self._s[1641]! } + public var Group_Management_AddModeratorHelp: String { return self._s[1642]! } + public var AutoDownloadSettings_WifiTitle: String { return self._s[1643]! } + public var Common_OK: String { return self._s[1644]! } + public var Passport_Address_TypeBankStatementUploadScan: String { return self._s[1645]! } + public var Wallet_Words_NotDoneResponse: String { return self._s[1646]! } + public var Cache_Music: String { return self._s[1647]! } + public var Wallet_Configuration_SourceURL: String { return self._s[1648]! } + public var SettingsSearch_Synonyms_EditProfile_PhoneNumber: String { return self._s[1649]! } + public var PasscodeSettings_UnlockWithTouchId: String { return self._s[1652]! } + public var TwoStepAuth_HintPlaceholder: String { return self._s[1653]! } public func PUSH_PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1648]!, self._r[1648]!, [_1]) + return formatWithArgumentRanges(self._s[1654]!, self._r[1654]!, [_1]) } public func Passport_RequestHeader(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1649]!, self._r[1649]!, [_0]) + return formatWithArgumentRanges(self._s[1655]!, self._r[1655]!, [_0]) } - public var TwoFactorSetup_Done_Action: String { return self._s[1650]! } + public var TwoFactorSetup_Done_Action: String { return self._s[1656]! } public func VoiceOver_Chat_ContactOrganization(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1651]!, self._r[1651]!, [_0]) + return formatWithArgumentRanges(self._s[1657]!, self._r[1657]!, [_0]) } - public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1652]! } - public var Watch_MessageView_ViewOnPhone: String { return self._s[1654]! } - public var Privacy_Calls_CustomShareHelp: String { return self._s[1655]! } - public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1657]! } - public var ChangePhoneNumberNumber_Title: String { return self._s[1658]! } - public var State_ConnectingToProxyInfo: String { return self._s[1659]! } - public var Conversation_SwipeToReplyHintTitle: String { return self._s[1660]! } - public var Message_VideoMessage: String { return self._s[1662]! } - public var ChannelInfo_DeleteChannel: String { return self._s[1663]! } - public var ContactInfo_PhoneLabelOther: String { return self._s[1664]! } - public var Channel_EditAdmin_CannotEdit: String { return self._s[1665]! } - public var Passport_DeleteAddressConfirmation: String { return self._s[1666]! } + public var Wallet_Send_ErrorNotEnoughFundsText: String { return self._s[1658]! } + public var Watch_MessageView_ViewOnPhone: String { return self._s[1660]! } + public var Privacy_Calls_CustomShareHelp: String { return self._s[1661]! } + public var Wallet_Receive_CreateInvoiceInfo: String { return self._s[1663]! } + public var ChangePhoneNumberNumber_Title: String { return self._s[1664]! } + public var State_ConnectingToProxyInfo: String { return self._s[1665]! } + public var Conversation_SwipeToReplyHintTitle: String { return self._s[1666]! } + public var Message_VideoMessage: String { return self._s[1668]! } + public var ChannelInfo_DeleteChannel: String { return self._s[1669]! } + public var ContactInfo_PhoneLabelOther: String { return self._s[1670]! } + public var Channel_EditAdmin_CannotEdit: String { return self._s[1671]! } + public var Passport_DeleteAddressConfirmation: String { return self._s[1672]! } public func Wallet_Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1667]!, self._r[1667]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1673]!, self._r[1673]!, [_1, _2, _3]) } - public var WallpaperPreview_SwipeBottomText: String { return self._s[1668]! } - public var Activity_RecordingAudio: String { return self._s[1669]! } - public var SettingsSearch_Synonyms_Watch: String { return self._s[1670]! } - public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1671]! } - public var Wallet_Info_Address: String { return self._s[1672]! } + public var WallpaperPreview_SwipeBottomText: String { return self._s[1674]! } + public var Activity_RecordingAudio: String { return self._s[1675]! } + public var SettingsSearch_Synonyms_Watch: String { return self._s[1676]! } + public var PasscodeSettings_TryAgainIn1Minute: String { return self._s[1677]! } + public var Wallet_Info_Address: String { return self._s[1678]! } public func Notification_ChangedGroupName(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1674]!, self._r[1674]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1680]!, self._r[1680]!, [_0, _1]) } public func EmptyGroupInfo_Line1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1678]!, self._r[1678]!, [_0]) + return formatWithArgumentRanges(self._s[1684]!, self._r[1684]!, [_0]) } - public var Conversation_ApplyLocalization: String { return self._s[1679]! } - public var TwoFactorSetup_Intro_Action: String { return self._s[1680]! } - public var UserInfo_AddPhone: String { return self._s[1681]! } - public var Map_ShareLiveLocationHelp: String { return self._s[1682]! } + public var Conversation_ApplyLocalization: String { return self._s[1685]! } + public var TwoFactorSetup_Intro_Action: String { return self._s[1686]! } + public var UserInfo_AddPhone: String { return self._s[1687]! } + public var Map_ShareLiveLocationHelp: String { return self._s[1688]! } public func Passport_Identity_NativeNameGenericHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1683]!, self._r[1683]!, [_0]) + return formatWithArgumentRanges(self._s[1689]!, self._r[1689]!, [_0]) } - public var Passport_Scans: String { return self._s[1685]! } - public var BlockedUsers_Unblock: String { return self._s[1686]! } + public var Passport_Scans: String { return self._s[1691]! } + public var BlockedUsers_Unblock: String { return self._s[1692]! } public func PUSH_ENCRYPTION_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1687]!, self._r[1687]!, [_1]) + return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_1]) } - public var Channel_Management_LabelCreator: String { return self._s[1688]! } - public var Conversation_ReportSpamAndLeave: String { return self._s[1689]! } - public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1690]! } - public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1691]! } - public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1692]! } + public var Channel_Management_LabelCreator: String { return self._s[1694]! } + public var Conversation_ReportSpamAndLeave: String { return self._s[1695]! } + public var SettingsSearch_Synonyms_EditProfile_Bio: String { return self._s[1696]! } + public var ChatList_UndoArchiveMultipleTitle: String { return self._s[1697]! } + public var Passport_Identity_NativeNameGenericTitle: String { return self._s[1698]! } public func Login_EmailPhoneBody(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1693]!, self._r[1693]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[1699]!, self._r[1699]!, [_0, _1, _2]) } - public var Login_PhoneNumberHelp: String { return self._s[1694]! } - public var LastSeen_ALongTimeAgo: String { return self._s[1695]! } - public var Channel_AdminLog_CanPinMessages: String { return self._s[1696]! } - public var ChannelIntro_CreateChannel: String { return self._s[1697]! } - public var Conversation_UnreadMessages: String { return self._s[1698]! } - public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1699]! } - public var Channel_AdminLog_EmptyText: String { return self._s[1700]! } - public var Theme_Context_Apply: String { return self._s[1701]! } - public var Notification_GroupActivated: String { return self._s[1702]! } - public var NotificationSettings_ContactJoinedInfo: String { return self._s[1703]! } - public var Wallet_Intro_CreateWallet: String { return self._s[1704]! } + public var Login_PhoneNumberHelp: String { return self._s[1700]! } + public var LastSeen_ALongTimeAgo: String { return self._s[1701]! } + public var Channel_AdminLog_CanPinMessages: String { return self._s[1702]! } + public var ChannelIntro_CreateChannel: String { return self._s[1703]! } + public var Conversation_UnreadMessages: String { return self._s[1704]! } + public var SettingsSearch_Synonyms_Stickers_ArchivedPacks: String { return self._s[1705]! } + public var Channel_AdminLog_EmptyText: String { return self._s[1706]! } + public var Theme_Context_Apply: String { return self._s[1707]! } + public var Notification_GroupActivated: String { return self._s[1708]! } + public var NotificationSettings_ContactJoinedInfo: String { return self._s[1709]! } + public var Wallet_Intro_CreateWallet: String { return self._s[1710]! } public func Notification_PinnedContactMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1705]!, self._r[1705]!, [_0]) + return formatWithArgumentRanges(self._s[1711]!, self._r[1711]!, [_0]) } public func DownloadingStatus(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1706]!, self._r[1706]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0, _1]) } - public var GroupInfo_ConvertToSupergroup: String { return self._s[1708]! } + public var GroupInfo_ConvertToSupergroup: String { return self._s[1714]! } public func PrivacyPolicy_AgeVerificationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1709]!, self._r[1709]!, [_0]) + return formatWithArgumentRanges(self._s[1715]!, self._r[1715]!, [_0]) } - public var Undo_DeletedChannel: String { return self._s[1710]! } - public var CallFeedback_AddComment: String { return self._s[1711]! } + public var Undo_DeletedChannel: String { return self._s[1716]! } + public var CallFeedback_AddComment: String { return self._s[1717]! } public func Conversation_OpenBotLinkAllowMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1712]!, self._r[1712]!, [_0]) + return formatWithArgumentRanges(self._s[1718]!, self._r[1718]!, [_0]) } - public var Document_TargetConfirmationFormat: String { return self._s[1713]! } + public var Document_TargetConfirmationFormat: String { return self._s[1719]! } public func Call_StatusOngoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1714]!, self._r[1714]!, [_0]) + return formatWithArgumentRanges(self._s[1720]!, self._r[1720]!, [_0]) } - public var LogoutOptions_SetPasscodeTitle: String { return self._s[1715]! } + public var LogoutOptions_SetPasscodeTitle: String { return self._s[1721]! } public func PUSH_CHAT_MESSAGE_GAME_SCORE(_ _1: String, _ _2: String, _ _3: String, _ _4: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1716]!, self._r[1716]!, [_1, _2, _3, _4]) + return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1, _2, _3, _4]) } - public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1717]! } - public var Theme_ErrorNotFound: String { return self._s[1718]! } - public var Contacts_SortByName: String { return self._s[1719]! } - public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1720]! } + public var Wallet_SecureStorageChanged_PasscodeText: String { return self._s[1723]! } + public var Theme_ErrorNotFound: String { return self._s[1724]! } + public var Contacts_SortByName: String { return self._s[1725]! } + public var SettingsSearch_Synonyms_Privacy_Forwards: String { return self._s[1726]! } public func CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1722]!, self._r[1722]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1728]!, self._r[1728]!, [_1, _2, _3]) } - public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1723]! } - public var ScheduledMessages_EditTime: String { return self._s[1724]! } - public var Conversation_ClearSelfHistory: String { return self._s[1725]! } - public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1726]! } - public var PasscodeSettings_DoNotMatch: String { return self._s[1727]! } - public var Stickers_SuggestNone: String { return self._s[1728]! } - public var ChatSettings_Cache: String { return self._s[1729]! } - public var Settings_SaveIncomingPhotos: String { return self._s[1730]! } - public var Media_ShareThisPhoto: String { return self._s[1731]! } - public var Chat_SlowmodeTooltipPending: String { return self._s[1732]! } - public var InfoPlist_NSContactsUsageDescription: String { return self._s[1733]! } - public var Conversation_ContextMenuCopyLink: String { return self._s[1734]! } - public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1735]! } - public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1736]! } - public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1737]! } - public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1738]! } + public var Notification_Exceptions_RemoveFromExceptions: String { return self._s[1729]! } + public var ScheduledMessages_EditTime: String { return self._s[1730]! } + public var Conversation_ClearSelfHistory: String { return self._s[1731]! } + public var Checkout_NewCard_PostcodePlaceholder: String { return self._s[1732]! } + public var PasscodeSettings_DoNotMatch: String { return self._s[1733]! } + public var Stickers_SuggestNone: String { return self._s[1734]! } + public var ChatSettings_Cache: String { return self._s[1735]! } + public var Settings_SaveIncomingPhotos: String { return self._s[1736]! } + public var Media_ShareThisPhoto: String { return self._s[1737]! } + public var Chat_SlowmodeTooltipPending: String { return self._s[1738]! } + public var InfoPlist_NSContactsUsageDescription: String { return self._s[1739]! } + public var Conversation_ContextMenuCopyLink: String { return self._s[1740]! } + public var PrivacyPolicy_AgeVerificationTitle: String { return self._s[1741]! } + public var SettingsSearch_Synonyms_Stickers_Masks: String { return self._s[1742]! } + public var TwoStepAuth_SetupPasswordEnterPasswordNew: String { return self._s[1743]! } + public var Appearance_ThemePreview_Chat_6_Text: String { return self._s[1744]! } public func Wallet_SecureStorageReset_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1739]!, self._r[1739]!, [_0]) + return formatWithArgumentRanges(self._s[1745]!, self._r[1745]!, [_0]) } - public var Permissions_CellularDataTitle_v0: String { return self._s[1740]! } - public var WallpaperSearch_ColorWhite: String { return self._s[1742]! } - public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1743]! } - public var Conversation_ErrorInaccessibleMessage: String { return self._s[1744]! } - public var Map_OpenIn: String { return self._s[1745]! } + public var Permissions_CellularDataTitle_v0: String { return self._s[1746]! } + public var WallpaperSearch_ColorWhite: String { return self._s[1748]! } + public var Channel_AdminLog_DefaultRestrictionsUpdated: String { return self._s[1749]! } + public var Conversation_ErrorInaccessibleMessage: String { return self._s[1750]! } + public var Map_OpenIn: String { return self._s[1751]! } public func PUSH_PHONE_CALL_MISSED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1748]!, self._r[1748]!, [_1]) + return formatWithArgumentRanges(self._s[1754]!, self._r[1754]!, [_1]) } public func ChannelInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1749]!, self._r[1749]!, [_0]) + return formatWithArgumentRanges(self._s[1755]!, self._r[1755]!, [_0]) } - public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1750]! } - public var MessagePoll_LabelClosed: String { return self._s[1751]! } - public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1753]! } - public var Wallet_Send_SendAnyway: String { return self._s[1754]! } - public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1755]! } - public var UserInfo_FirstNamePlaceholder: String { return self._s[1756]! } - public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1757]! } - public var Map_SetThisPlace: String { return self._s[1758]! } - public var Login_SelectCountry_Title: String { return self._s[1759]! } - public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1760]! } + public var GroupInfo_Permissions_SlowmodeHeader: String { return self._s[1756]! } + public var MessagePoll_LabelClosed: String { return self._s[1757]! } + public var GroupPermission_PermissionGloballyDisabled: String { return self._s[1759]! } + public var Wallet_Send_SendAnyway: String { return self._s[1760]! } + public var Passport_Identity_MiddleNamePlaceholder: String { return self._s[1761]! } + public var UserInfo_FirstNamePlaceholder: String { return self._s[1762]! } + public var PrivacyLastSeenSettings_WhoCanSeeMyTimestamp: String { return self._s[1763]! } + public var Map_SetThisPlace: String { return self._s[1764]! } + public var Login_SelectCountry_Title: String { return self._s[1765]! } + public var Channel_EditAdmin_PermissionBanUsers: String { return self._s[1766]! } public func Conversation_OpenBotLinkLogin(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1761]!, self._r[1761]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1767]!, self._r[1767]!, [_1, _2]) } - public var Channel_AdminLog_ChangeInfo: String { return self._s[1762]! } - public var Watch_Suggestion_BRB: String { return self._s[1763]! } - public var Passport_Identity_EditIdentityCard: String { return self._s[1764]! } - public var Contacts_PermissionsTitle: String { return self._s[1765]! } - public var Conversation_RestrictedInline: String { return self._s[1766]! } - public var Appearance_RemoveThemeColor: String { return self._s[1768]! } - public var StickerPack_ViewPack: String { return self._s[1769]! } - public var Wallet_UnknownError: String { return self._s[1770]! } + public var Channel_AdminLog_ChangeInfo: String { return self._s[1768]! } + public var Watch_Suggestion_BRB: String { return self._s[1769]! } + public var Passport_Identity_EditIdentityCard: String { return self._s[1770]! } + public var Contacts_PermissionsTitle: String { return self._s[1771]! } + public var Conversation_RestrictedInline: String { return self._s[1772]! } + public var Appearance_RemoveThemeColor: String { return self._s[1774]! } + public var StickerPack_ViewPack: String { return self._s[1775]! } + public var Wallet_UnknownError: String { return self._s[1776]! } public func Update_AppVersion(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1771]!, self._r[1771]!, [_0]) + return formatWithArgumentRanges(self._s[1777]!, self._r[1777]!, [_0]) } - public var Compose_NewChannel: String { return self._s[1773]! } - public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1776]! } - public var MessagePoll_LabelQuiz: String { return self._s[1778]! } - public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1779]! } - public var Channel_Info_Stickers: String { return self._s[1780]! } - public var AutoNightTheme_PreferredTheme: String { return self._s[1781]! } - public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1782]! } - public var Passport_DeletePersonalDetails: String { return self._s[1783]! } - public var LogoutOptions_AddAccountTitle: String { return self._s[1784]! } - public var Channel_DiscussionGroupInfo: String { return self._s[1785]! } - public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1786]! } - public var Conversation_SearchNoResults: String { return self._s[1789]! } - public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1790]! } - public var MessagePoll_LabelAnonymous: String { return self._s[1791]! } - public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1792]! } - public var Login_Code: String { return self._s[1793]! } - public var EditTheme_Create_BottomInfo: String { return self._s[1794]! } - public var Watch_Suggestion_WhatsUp: String { return self._s[1795]! } - public var Weekday_ShortThursday: String { return self._s[1796]! } - public var Resolve_ErrorNotFound: String { return self._s[1798]! } - public var LastSeen_Offline: String { return self._s[1799]! } - public var PeopleNearby_NoMembers: String { return self._s[1800]! } - public var GroupPermission_AddMembersNotAvailable: String { return self._s[1801]! } - public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1802]! } - public var GroupInfo_Title: String { return self._s[1804]! } - public var NotificationsSound_Note: String { return self._s[1805]! } - public var Conversation_EditingMessagePanelTitle: String { return self._s[1806]! } - public var Watch_Message_Poll: String { return self._s[1807]! } - public var Privacy_Calls: String { return self._s[1808]! } + public var Compose_NewChannel: String { return self._s[1779]! } + public var ChatSettings_AutoDownloadSettings_TypePhoto: String { return self._s[1782]! } + public var MessagePoll_LabelQuiz: String { return self._s[1784]! } + public var Conversation_ReportSpamGroupConfirmation: String { return self._s[1785]! } + public var Channel_Info_Stickers: String { return self._s[1786]! } + public var AutoNightTheme_PreferredTheme: String { return self._s[1787]! } + public var PrivacyPolicy_AgeVerificationAgree: String { return self._s[1788]! } + public var Passport_DeletePersonalDetails: String { return self._s[1789]! } + public var LogoutOptions_AddAccountTitle: String { return self._s[1790]! } + public var Channel_DiscussionGroupInfo: String { return self._s[1791]! } + public var Group_EditAdmin_RankOwnerPlaceholder: String { return self._s[1792]! } + public var Conversation_SearchNoResults: String { return self._s[1795]! } + public var Wallet_Configuration_ApplyErrorTextURLInvalid: String { return self._s[1796]! } + public var MessagePoll_LabelAnonymous: String { return self._s[1797]! } + public var Channel_Members_AddAdminErrorNotAMember: String { return self._s[1798]! } + public var Login_Code: String { return self._s[1799]! } + public var EditTheme_Create_BottomInfo: String { return self._s[1800]! } + public var Watch_Suggestion_WhatsUp: String { return self._s[1801]! } + public var Weekday_ShortThursday: String { return self._s[1802]! } + public var Resolve_ErrorNotFound: String { return self._s[1804]! } + public var LastSeen_Offline: String { return self._s[1805]! } + public var PeopleNearby_NoMembers: String { return self._s[1806]! } + public var GroupPermission_AddMembersNotAvailable: String { return self._s[1807]! } + public var Privacy_Calls_AlwaysAllow_Title: String { return self._s[1808]! } + public var GroupInfo_Title: String { return self._s[1810]! } + public var NotificationsSound_Note: String { return self._s[1811]! } + public var Conversation_EditingMessagePanelTitle: String { return self._s[1812]! } + public var Watch_Message_Poll: String { return self._s[1813]! } + public var Privacy_Calls: String { return self._s[1814]! } public func Channel_AdminLog_MessageRankUsername(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1809]!, self._r[1809]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1815]!, self._r[1815]!, [_1, _2, _3]) } - public var Month_ShortAugust: String { return self._s[1810]! } - public var TwoStepAuth_SetPasswordHelp: String { return self._s[1811]! } - public var Notifications_Reset: String { return self._s[1812]! } - public var Conversation_Pin: String { return self._s[1813]! } - public var Passport_Language_lv: String { return self._s[1814]! } - public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1815]! } - public var BlockedUsers_Info: String { return self._s[1816]! } - public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1818]! } - public var Watch_Conversation_Unblock: String { return self._s[1820]! } + public var Month_ShortAugust: String { return self._s[1816]! } + public var TwoStepAuth_SetPasswordHelp: String { return self._s[1817]! } + public var Notifications_Reset: String { return self._s[1818]! } + public var Conversation_Pin: String { return self._s[1819]! } + public var Passport_Language_lv: String { return self._s[1820]! } + public var Permissions_PeopleNearbyAllowInSettings_v0: String { return self._s[1821]! } + public var BlockedUsers_Info: String { return self._s[1822]! } + public var SettingsSearch_Synonyms_Data_AutoplayVideos: String { return self._s[1824]! } + public var Watch_Conversation_Unblock: String { return self._s[1826]! } public func Time_MonthOfYear_m9(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1821]!, self._r[1821]!, [_0]) + return formatWithArgumentRanges(self._s[1827]!, self._r[1827]!, [_0]) } - public var CloudStorage_Title: String { return self._s[1822]! } - public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1823]! } + public var CloudStorage_Title: String { return self._s[1828]! } + public var GroupInfo_DeleteAndExitConfirmation: String { return self._s[1829]! } public func NetworkUsageSettings_WifiUsageSince(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1824]!, self._r[1824]!, [_0]) + return formatWithArgumentRanges(self._s[1830]!, self._r[1830]!, [_0]) } - public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1825]! } - public var Watch_Suggestion_OnMyWay: String { return self._s[1826]! } - public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1827]! } - public var Passport_Address_EditBankStatement: String { return self._s[1828]! } + public var Channel_AdminLogFilter_AdminsTitle: String { return self._s[1831]! } + public var Watch_Suggestion_OnMyWay: String { return self._s[1832]! } + public var TwoStepAuth_RecoveryEmailTitle: String { return self._s[1833]! } + public var Passport_Address_EditBankStatement: String { return self._s[1834]! } public func Channel_AdminLog_MessageChangedUnlinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1829]!, self._r[1829]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1835]!, self._r[1835]!, [_1, _2]) } - public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1830]! } - public var ShareMenu_Comment: String { return self._s[1831]! } - public var Permissions_ContactsTitle_v0: String { return self._s[1832]! } - public var Notifications_PermissionsTitle: String { return self._s[1833]! } - public var GroupPermission_NoSendLinks: String { return self._s[1834]! } - public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1835]! } - public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1836]! } - public var Settings_Support: String { return self._s[1837]! } - public var Notifications_ChannelNotificationsSound: String { return self._s[1838]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1839]! } - public var Privacy_Forwards_Preview: String { return self._s[1840]! } - public var GroupPermission_ApplyAlertAction: String { return self._s[1841]! } - public var Watch_Stickers_StickerPacks: String { return self._s[1842]! } - public var Common_Select: String { return self._s[1844]! } - public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1845]! } - public var WallpaperSearch_ColorGray: String { return self._s[1848]! } - public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1849]! } - public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1850]! } - public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1851]! } - public var PollResults_Title: String { return self._s[1852]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1853]! } - public var Appearance_PreviewReplyAuthor: String { return self._s[1854]! } - public var TwoStepAuth_RecoveryTitle: String { return self._s[1855]! } - public var Widget_AuthRequired: String { return self._s[1856]! } - public var Camera_FlashOn: String { return self._s[1857]! } - public var Conversation_ContextMenuLookUp: String { return self._s[1858]! } - public var Channel_Stickers_NotFoundHelp: String { return self._s[1859]! } - public var Watch_Suggestion_OK: String { return self._s[1860]! } + public var ChatSettings_DownloadInBackgroundInfo: String { return self._s[1836]! } + public var ShareMenu_Comment: String { return self._s[1837]! } + public var Permissions_ContactsTitle_v0: String { return self._s[1838]! } + public var Notifications_PermissionsTitle: String { return self._s[1839]! } + public var GroupPermission_NoSendLinks: String { return self._s[1840]! } + public var Privacy_Forwards_NeverAllow_Title: String { return self._s[1841]! } + public var Wallet_SecureStorageChanged_ImportWallet: String { return self._s[1842]! } + public var Settings_Support: String { return self._s[1843]! } + public var Notifications_ChannelNotificationsSound: String { return self._s[1844]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadReset: String { return self._s[1845]! } + public var Privacy_Forwards_Preview: String { return self._s[1846]! } + public var GroupPermission_ApplyAlertAction: String { return self._s[1847]! } + public var Watch_Stickers_StickerPacks: String { return self._s[1848]! } + public var Common_Select: String { return self._s[1850]! } + public var CheckoutInfo_ErrorEmailInvalid: String { return self._s[1851]! } + public var WallpaperSearch_ColorGray: String { return self._s[1854]! } + public var TwoFactorSetup_Password_PlaceholderPassword: String { return self._s[1855]! } + public var TwoFactorSetup_Hint_SkipAction: String { return self._s[1856]! } + public var ChatAdmins_AllMembersAreAdminsOffHelp: String { return self._s[1857]! } + public var PollResults_Title: String { return self._s[1858]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5hours: String { return self._s[1859]! } + public var Appearance_PreviewReplyAuthor: String { return self._s[1860]! } + public var TwoStepAuth_RecoveryTitle: String { return self._s[1861]! } + public var Widget_AuthRequired: String { return self._s[1862]! } + public var Camera_FlashOn: String { return self._s[1863]! } + public var Conversation_ContextMenuLookUp: String { return self._s[1864]! } + public var Channel_Stickers_NotFoundHelp: String { return self._s[1865]! } + public var Watch_Suggestion_OK: String { return self._s[1866]! } public func Username_LinkHint(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1862]!, self._r[1862]!, [_0]) + return formatWithArgumentRanges(self._s[1868]!, self._r[1868]!, [_0]) } public func Notification_PinnedLiveLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1864]!, self._r[1864]!, [_0]) + return formatWithArgumentRanges(self._s[1870]!, self._r[1870]!, [_0]) } - public var TextFormat_Strikethrough: String { return self._s[1865]! } - public var DialogList_AdLabel: String { return self._s[1866]! } - public var WatchRemote_NotificationText: String { return self._s[1867]! } - public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1868]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1869]! } - public var Conversation_ReportSpam: String { return self._s[1870]! } - public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1871]! } - public var Settings_LogoutConfirmationTitle: String { return self._s[1873]! } - public var PhoneLabel_Title: String { return self._s[1874]! } - public var Passport_Address_EditRentalAgreement: String { return self._s[1875]! } - public var Settings_ChangePhoneNumber: String { return self._s[1876]! } - public var Notifications_ExceptionsTitle: String { return self._s[1877]! } - public var Notifications_AlertTones: String { return self._s[1878]! } - public var Call_ReportIncludeLogDescription: String { return self._s[1879]! } - public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1880]! } - public var AutoDownloadSettings_PrivateChats: String { return self._s[1881]! } - public var VoiceOver_Chat_Photo: String { return self._s[1883]! } - public var TwoStepAuth_AddHintTitle: String { return self._s[1884]! } - public var ReportPeer_ReasonOther: String { return self._s[1885]! } - public var ChatList_Context_JoinChannel: String { return self._s[1886]! } - public var KeyCommand_ScrollDown: String { return self._s[1888]! } - public var Conversation_ScheduleMessage_Title: String { return self._s[1889]! } + public var TextFormat_Strikethrough: String { return self._s[1871]! } + public var DialogList_AdLabel: String { return self._s[1872]! } + public var WatchRemote_NotificationText: String { return self._s[1873]! } + public var IntentsSettings_SuggestedChatsSavedMessages: String { return self._s[1874]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsAlert: String { return self._s[1875]! } + public var Conversation_ReportSpam: String { return self._s[1876]! } + public var SettingsSearch_Synonyms_Privacy_Data_TopPeers: String { return self._s[1877]! } + public var Settings_LogoutConfirmationTitle: String { return self._s[1879]! } + public var PhoneLabel_Title: String { return self._s[1880]! } + public var Passport_Address_EditRentalAgreement: String { return self._s[1881]! } + public var Settings_ChangePhoneNumber: String { return self._s[1882]! } + public var Notifications_ExceptionsTitle: String { return self._s[1883]! } + public var Notifications_AlertTones: String { return self._s[1884]! } + public var Call_ReportIncludeLogDescription: String { return self._s[1885]! } + public var SettingsSearch_Synonyms_Notifications_ResetAllNotifications: String { return self._s[1886]! } + public var AutoDownloadSettings_PrivateChats: String { return self._s[1887]! } + public var VoiceOver_Chat_Photo: String { return self._s[1889]! } + public var TwoStepAuth_AddHintTitle: String { return self._s[1890]! } + public var ReportPeer_ReasonOther: String { return self._s[1891]! } + public var ChatList_Context_JoinChannel: String { return self._s[1892]! } + public var KeyCommand_ScrollDown: String { return self._s[1894]! } + public var Conversation_ScheduleMessage_Title: String { return self._s[1895]! } public func Login_BannedPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1890]!, self._r[1890]!, [_0]) + return formatWithArgumentRanges(self._s[1896]!, self._r[1896]!, [_0]) } - public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1891]! } - public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1892]! } - public var AuthSessions_LogOut: String { return self._s[1893]! } - public var Passport_Identity_TypeInternalPassport: String { return self._s[1894]! } - public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1895]! } - public var Passport_Phone_Title: String { return self._s[1896]! } - public var ContactList_Context_StartSecretChat: String { return self._s[1897]! } - public var Settings_PhoneNumber: String { return self._s[1898]! } + public var NetworkUsageSettings_MediaVideoDataSection: String { return self._s[1897]! } + public var ChannelInfo_DeleteGroupConfirmation: String { return self._s[1898]! } + public var AuthSessions_LogOut: String { return self._s[1899]! } + public var Passport_Identity_TypeInternalPassport: String { return self._s[1900]! } + public var ChatSettings_AutoDownloadVoiceMessages: String { return self._s[1901]! } + public var Passport_Phone_Title: String { return self._s[1902]! } + public var ContactList_Context_StartSecretChat: String { return self._s[1903]! } + public var Settings_PhoneNumber: String { return self._s[1904]! } public func Conversation_ScheduleMessage_SendToday(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1899]!, self._r[1899]!, [_0]) + return formatWithArgumentRanges(self._s[1905]!, self._r[1905]!, [_0]) } - public var NotificationsSound_Alert: String { return self._s[1901]! } - public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1902]! } - public var WebSearch_SearchNoResults: String { return self._s[1903]! } - public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1905]! } - public var Wallet_Configuration_SourceInfo: String { return self._s[1906]! } - public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1907]! } - public var SettingsSearch_Synonyms_Passport: String { return self._s[1908]! } - public var PhotoEditor_CurvesTool: String { return self._s[1909]! } - public var Checkout_PaymentMethod: String { return self._s[1911]! } + public var NotificationsSound_Alert: String { return self._s[1907]! } + public var Wallet_SecureStorageChanged_CreateWallet: String { return self._s[1908]! } + public var WebSearch_SearchNoResults: String { return self._s[1909]! } + public var Privacy_ProfilePhoto_AlwaysShareWith_Title: String { return self._s[1911]! } + public var Wallet_Configuration_SourceInfo: String { return self._s[1912]! } + public var LogoutOptions_AlternativeOptionsSection: String { return self._s[1913]! } + public var SettingsSearch_Synonyms_Passport: String { return self._s[1914]! } + public var PhotoEditor_CurvesTool: String { return self._s[1915]! } + public var Checkout_PaymentMethod: String { return self._s[1917]! } public func PUSH_CHAT_ADD_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1912]!, self._r[1912]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1918]!, self._r[1918]!, [_1, _2]) } - public var Contacts_AccessDeniedError: String { return self._s[1913]! } - public var Camera_PhotoMode: String { return self._s[1916]! } - public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1917]! } - public var Appearance_TextSize_Apply: String { return self._s[1918]! } - public var Passport_Address_AddUtilityBill: String { return self._s[1920]! } - public var CallSettings_OnMobile: String { return self._s[1921]! } - public var Tour_Text2: String { return self._s[1922]! } + public var Contacts_AccessDeniedError: String { return self._s[1919]! } + public var Camera_PhotoMode: String { return self._s[1922]! } + public var EditTheme_Expand_Preview_IncomingText: String { return self._s[1923]! } + public var Appearance_TextSize_Apply: String { return self._s[1924]! } + public var Passport_Address_AddUtilityBill: String { return self._s[1926]! } + public var CallSettings_OnMobile: String { return self._s[1927]! } + public var Tour_Text2: String { return self._s[1928]! } public func PUSH_CHAT_MESSAGE_ROUND(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1923]!, self._r[1923]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1929]!, self._r[1929]!, [_1, _2]) } - public var DialogList_EncryptionProcessing: String { return self._s[1925]! } - public var Permissions_Skip: String { return self._s[1926]! } - public var Wallet_Words_NotDoneOk: String { return self._s[1927]! } - public var SecretImage_Title: String { return self._s[1928]! } - public var Watch_MessageView_Title: String { return self._s[1929]! } - public var Channel_DiscussionGroupAdd: String { return self._s[1930]! } - public var AttachmentMenu_Poll: String { return self._s[1931]! } + public var DialogList_EncryptionProcessing: String { return self._s[1931]! } + public var Permissions_Skip: String { return self._s[1932]! } + public var Wallet_Words_NotDoneOk: String { return self._s[1933]! } + public var SecretImage_Title: String { return self._s[1934]! } + public var Watch_MessageView_Title: String { return self._s[1935]! } + public var Channel_DiscussionGroupAdd: String { return self._s[1936]! } + public var AttachmentMenu_Poll: String { return self._s[1937]! } public func Notification_GroupInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1932]!, self._r[1932]!, [_0]) + return formatWithArgumentRanges(self._s[1938]!, self._r[1938]!, [_0]) } public func Channel_DiscussionGroup_PrivateChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1933]!, self._r[1933]!, [_1, _2]) + return formatWithArgumentRanges(self._s[1939]!, self._r[1939]!, [_1, _2]) } - public var Notification_CallCanceled: String { return self._s[1934]! } - public var WallpaperPreview_Title: String { return self._s[1935]! } - public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1936]! } - public var Settings_ProxyConnecting: String { return self._s[1937]! } - public var Settings_CheckPhoneNumberText: String { return self._s[1939]! } - public var VoiceOver_Chat_YourVideo: String { return self._s[1940]! } - public var Wallet_Intro_Title: String { return self._s[1941]! } - public var TwoFactorSetup_Password_Action: String { return self._s[1942]! } - public var Profile_MessageLifetime5s: String { return self._s[1943]! } - public var Username_InvalidCharacters: String { return self._s[1944]! } - public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1945]! } - public var ScheduledMessages_ClearAll: String { return self._s[1946]! } - public var WallpaperPreview_CropBottomText: String { return self._s[1947]! } - public var AutoDownloadSettings_LimitBySize: String { return self._s[1948]! } - public var Settings_AddAccount: String { return self._s[1949]! } - public var Notification_CreatedChannel: String { return self._s[1952]! } + public var Notification_CallCanceled: String { return self._s[1940]! } + public var WallpaperPreview_Title: String { return self._s[1941]! } + public var Privacy_PaymentsClear_PaymentInfo: String { return self._s[1942]! } + public var Settings_ProxyConnecting: String { return self._s[1943]! } + public var Settings_CheckPhoneNumberText: String { return self._s[1945]! } + public var VoiceOver_Chat_YourVideo: String { return self._s[1946]! } + public var Wallet_Intro_Title: String { return self._s[1947]! } + public var TwoFactorSetup_Password_Action: String { return self._s[1948]! } + public var Profile_MessageLifetime5s: String { return self._s[1949]! } + public var Username_InvalidCharacters: String { return self._s[1950]! } + public var VoiceOver_Media_PlaybackRateFast: String { return self._s[1951]! } + public var ScheduledMessages_ClearAll: String { return self._s[1952]! } + public var WallpaperPreview_CropBottomText: String { return self._s[1953]! } + public var AutoDownloadSettings_LimitBySize: String { return self._s[1954]! } + public var Settings_AddAccount: String { return self._s[1955]! } + public var Notification_CreatedChannel: String { return self._s[1958]! } public func PUSH_CHAT_DELETE_MEMBER(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1953]!, self._r[1953]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[1959]!, self._r[1959]!, [_1, _2, _3]) } - public var Passcode_AppLockedAlert: String { return self._s[1955]! } - public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1956]! } - public var VoiceOver_Media_PlaybackStop: String { return self._s[1957]! } - public var Contacts_TopSection: String { return self._s[1958]! } - public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1959]! } + public var Passcode_AppLockedAlert: String { return self._s[1961]! } + public var StickerPacksSettings_AnimatedStickersInfo: String { return self._s[1962]! } + public var VoiceOver_Media_PlaybackStop: String { return self._s[1963]! } + public var Contacts_TopSection: String { return self._s[1964]! } + public var ChatList_DeleteForEveryoneConfirmationAction: String { return self._s[1965]! } public func Conversation_SetReminder_RemindOn(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1960]!, self._r[1960]!, [_0, _1]) + return formatWithArgumentRanges(self._s[1966]!, self._r[1966]!, [_0, _1]) } - public var Wallet_Info_Receive: String { return self._s[1961]! } - public var Wallet_Completed_ViewWallet: String { return self._s[1962]! } + public var Wallet_Info_Receive: String { return self._s[1967]! } + public var Wallet_Completed_ViewWallet: String { return self._s[1968]! } public func Time_MonthOfYear_m6(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1963]!, self._r[1963]!, [_0]) + return formatWithArgumentRanges(self._s[1969]!, self._r[1969]!, [_0]) } - public var ReportPeer_ReasonSpam: String { return self._s[1964]! } - public var UserInfo_TapToCall: String { return self._s[1965]! } - public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1967]! } - public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1968]! } - public var Common_Search: String { return self._s[1969]! } - public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1970]! } + public var ReportPeer_ReasonSpam: String { return self._s[1970]! } + public var UserInfo_TapToCall: String { return self._s[1971]! } + public var Conversation_ForwardAuthorHiddenTooltip: String { return self._s[1973]! } + public var AutoDownloadSettings_DataUsageCustom: String { return self._s[1974]! } + public var Common_Search: String { return self._s[1975]! } + public var ScheduledMessages_EmptyPlaceholder: String { return self._s[1976]! } public func Channel_AdminLog_MessageChangedGroupGeoLocation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1971]!, self._r[1971]!, [_0]) + return formatWithArgumentRanges(self._s[1977]!, self._r[1977]!, [_0]) } - public var Wallet_Month_ShortJuly: String { return self._s[1972]! } - public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1974]! } - public var Message_InvoiceLabel: String { return self._s[1975]! } - public var Conversation_InputTextPlaceholder: String { return self._s[1976]! } - public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1977]! } + public var Wallet_Month_ShortJuly: String { return self._s[1978]! } + public var AuthSessions_IncompleteAttemptsInfo: String { return self._s[1980]! } + public var Message_InvoiceLabel: String { return self._s[1981]! } + public var Conversation_InputTextPlaceholder: String { return self._s[1982]! } + public var NetworkUsageSettings_MediaImageDataSection: String { return self._s[1983]! } public func Passport_Address_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[1978]!, self._r[1978]!, [_0]) + return formatWithArgumentRanges(self._s[1984]!, self._r[1984]!, [_0]) } - public var IntentsSettings_Reset: String { return self._s[1979]! } - public var Conversation_Info: String { return self._s[1980]! } - public var Login_InfoDeletePhoto: String { return self._s[1981]! } - public var Passport_Language_vi: String { return self._s[1983]! } - public var UserInfo_ScamUserWarning: String { return self._s[1984]! } - public var Conversation_Search: String { return self._s[1985]! } - public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1987]! } - public var ReportPeer_ReasonPornography: String { return self._s[1988]! } - public var AutoDownloadSettings_PhotosTitle: String { return self._s[1989]! } - public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1990]! } - public var Map_LiveLocationGroupDescription: String { return self._s[1991]! } - public var Channel_Setup_TypeHeader: String { return self._s[1992]! } - public var AuthSessions_LoggedIn: String { return self._s[1993]! } - public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[1994]! } - public var Login_SmsRequestState3: String { return self._s[1995]! } - public var Passport_Address_EditUtilityBill: String { return self._s[1996]! } - public var Appearance_ReduceMotionInfo: String { return self._s[1997]! } - public var Join_ChannelsTooMuch: String { return self._s[1998]! } - public var Channel_Edit_LinkItem: String { return self._s[1999]! } - public var Privacy_Calls_P2PNever: String { return self._s[2000]! } - public var Conversation_AddToReadingList: String { return self._s[2002]! } - public var Share_MultipleMessagesDisabled: String { return self._s[2003]! } - public var Message_Animation: String { return self._s[2004]! } - public var Conversation_DefaultRestrictedMedia: String { return self._s[2005]! } - public var Map_Unknown: String { return self._s[2006]! } - public var AutoDownloadSettings_LastDelimeter: String { return self._s[2007]! } + public var IntentsSettings_Reset: String { return self._s[1985]! } + public var Conversation_Info: String { return self._s[1986]! } + public var Login_InfoDeletePhoto: String { return self._s[1987]! } + public var Passport_Language_vi: String { return self._s[1989]! } + public var UserInfo_ScamUserWarning: String { return self._s[1990]! } + public var Conversation_Search: String { return self._s[1991]! } + public var DialogList_DeleteBotConversationConfirmation: String { return self._s[1993]! } + public var ReportPeer_ReasonPornography: String { return self._s[1994]! } + public var AutoDownloadSettings_PhotosTitle: String { return self._s[1995]! } + public var Conversation_SendMessageErrorGroupRestricted: String { return self._s[1996]! } + public var Map_LiveLocationGroupDescription: String { return self._s[1997]! } + public var Channel_Setup_TypeHeader: String { return self._s[1998]! } + public var AuthSessions_LoggedIn: String { return self._s[1999]! } + public var Privacy_Forwards_AlwaysAllow_Title: String { return self._s[2000]! } + public var Login_SmsRequestState3: String { return self._s[2001]! } + public var Passport_Address_EditUtilityBill: String { return self._s[2002]! } + public var Appearance_ReduceMotionInfo: String { return self._s[2003]! } + public var Join_ChannelsTooMuch: String { return self._s[2004]! } + public var Channel_Edit_LinkItem: String { return self._s[2005]! } + public var Privacy_Calls_P2PNever: String { return self._s[2006]! } + public var Conversation_AddToReadingList: String { return self._s[2008]! } + public var Share_MultipleMessagesDisabled: String { return self._s[2009]! } + public var Message_Animation: String { return self._s[2010]! } + public var Conversation_DefaultRestrictedMedia: String { return self._s[2011]! } + public var Map_Unknown: String { return self._s[2012]! } + public var AutoDownloadSettings_LastDelimeter: String { return self._s[2013]! } public func PUSH_PINNED_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2008]!, self._r[2008]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_1, _2]) } public func Passport_FieldOneOf_Or(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2009]!, self._r[2009]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2015]!, self._r[2015]!, [_1, _2]) } - public var Call_StatusRequesting: String { return self._s[2010]! } - public var Conversation_SecretChatContextBotAlert: String { return self._s[2011]! } - public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2012]! } + public var Call_StatusRequesting: String { return self._s[2016]! } + public var Conversation_SecretChatContextBotAlert: String { return self._s[2017]! } + public var SocksProxySetup_ProxyStatusChecking: String { return self._s[2018]! } public func PUSH_CHAT_MESSAGE_DOC(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2013]!, self._r[2013]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1, _2]) } public func Notification_PinnedLocationMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2014]!, self._r[2014]!, [_0]) + return formatWithArgumentRanges(self._s[2020]!, self._r[2020]!, [_0]) } - public var Update_Skip: String { return self._s[2015]! } - public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2016]! } - public var Message_PinnedPollMessage: String { return self._s[2017]! } - public var BlockedUsers_Title: String { return self._s[2018]! } + public var Update_Skip: String { return self._s[2021]! } + public var Group_Username_RemoveExistingUsernamesInfo: String { return self._s[2022]! } + public var Message_PinnedPollMessage: String { return self._s[2023]! } + public var BlockedUsers_Title: String { return self._s[2024]! } public func PUSH_CHANNEL_MESSAGE_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2019]!, self._r[2019]!, [_1]) + return formatWithArgumentRanges(self._s[2025]!, self._r[2025]!, [_1]) } - public var Username_CheckingUsername: String { return self._s[2020]! } - public var NotificationsSound_Bell: String { return self._s[2021]! } - public var Conversation_SendMessageErrorFlood: String { return self._s[2022]! } - public var Weekday_Monday: String { return self._s[2023]! } - public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2024]! } - public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2025]! } - public var ChatSettings_Groups: String { return self._s[2026]! } - public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2027]! } + public var Username_CheckingUsername: String { return self._s[2026]! } + public var NotificationsSound_Bell: String { return self._s[2027]! } + public var Conversation_SendMessageErrorFlood: String { return self._s[2028]! } + public var Weekday_Monday: String { return self._s[2029]! } + public var SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen: String { return self._s[2030]! } + public var ChannelMembers_ChannelAdminsTitle: String { return self._s[2031]! } + public var ChatSettings_Groups: String { return self._s[2032]! } + public var WallpaperPreview_PatternPaternDiscard: String { return self._s[2033]! } public func Conversation_SetReminder_RemindTomorrow(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2028]!, self._r[2028]!, [_0]) + return formatWithArgumentRanges(self._s[2034]!, self._r[2034]!, [_0]) } - public var Your_card_was_declined: String { return self._s[2029]! } - public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2031]! } - public var Wallet_Month_ShortApril: String { return self._s[2032]! } - public var ChatList_Unmute: String { return self._s[2033]! } - public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2034]! } - public var PhotoEditor_CurvesAll: String { return self._s[2035]! } - public var Weekday_ShortTuesday: String { return self._s[2036]! } - public var DialogList_Read: String { return self._s[2037]! } - public var Appearance_AppIconClassic: String { return self._s[2038]! } - public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2039]! } - public var Passport_Identity_Gender: String { return self._s[2040]! } + public var Your_card_was_declined: String { return self._s[2035]! } + public var TwoStepAuth_EnterPasswordHelp: String { return self._s[2037]! } + public var Wallet_Month_ShortApril: String { return self._s[2038]! } + public var ChatList_Unmute: String { return self._s[2039]! } + public var AuthSessions_AddDevice_ScanTitle: String { return self._s[2040]! } + public var PhotoEditor_CurvesAll: String { return self._s[2041]! } + public var Weekday_ShortTuesday: String { return self._s[2042]! } + public var DialogList_Read: String { return self._s[2043]! } + public var Appearance_AppIconClassic: String { return self._s[2044]! } + public var ChannelMembers_WhoCanAddMembers_AllMembers: String { return self._s[2045]! } + public var Passport_Identity_Gender: String { return self._s[2046]! } public func Target_ShareGameConfirmationPrivate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2041]!, self._r[2041]!, [_0]) + return formatWithArgumentRanges(self._s[2047]!, self._r[2047]!, [_0]) } - public var Target_SelectGroup: String { return self._s[2042]! } - public var Map_HomeAndWorkInfo: String { return self._s[2044]! } + public var Target_SelectGroup: String { return self._s[2048]! } + public var Map_HomeAndWorkInfo: String { return self._s[2050]! } public func DialogList_EncryptedChatStartedIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2045]!, self._r[2045]!, [_0]) + return formatWithArgumentRanges(self._s[2051]!, self._r[2051]!, [_0]) } - public var Passport_Language_en: String { return self._s[2046]! } - public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2047]! } - public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2048]! } - public var Login_CancelPhoneVerificationContinue: String { return self._s[2049]! } - public var ScheduledMessages_SendNow: String { return self._s[2050]! } - public var Checkout_NewCard_PaymentCard: String { return self._s[2052]! } - public var Login_InfoHelp: String { return self._s[2053]! } - public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2054]! } - public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2055]! } + public var Passport_Language_en: String { return self._s[2052]! } + public var AutoDownloadSettings_AutodownloadPhotos: String { return self._s[2053]! } + public var Channel_Username_CreatePublicLinkHelp: String { return self._s[2054]! } + public var Login_CancelPhoneVerificationContinue: String { return self._s[2055]! } + public var ScheduledMessages_SendNow: String { return self._s[2056]! } + public var Checkout_NewCard_PaymentCard: String { return self._s[2058]! } + public var Login_InfoHelp: String { return self._s[2059]! } + public var Contacts_PermissionsSuppressWarningTitle: String { return self._s[2060]! } + public var SettingsSearch_Synonyms_Stickers_FeaturedPacks: String { return self._s[2061]! } public func Channel_AdminLog_MessageChangedLinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2056]!, self._r[2056]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2062]!, self._r[2062]!, [_1, _2]) } - public var SocksProxySetup_AddProxy: String { return self._s[2059]! } - public var CreatePoll_Title: String { return self._s[2060]! } - public var MessagePoll_QuizNoUsers: String { return self._s[2061]! } - public var Conversation_ViewTheme: String { return self._s[2062]! } - public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2063]! } - public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2064]! } - public var TwoFactorSetup_Intro_Text: String { return self._s[2065]! } - public var UserInfo_GroupsInCommon: String { return self._s[2066]! } - public var TelegramWallet_Intro_TermsUrl: String { return self._s[2067]! } - public var Call_AudioRouteHide: String { return self._s[2068]! } + public var SocksProxySetup_AddProxy: String { return self._s[2065]! } + public var CreatePoll_Title: String { return self._s[2066]! } + public var MessagePoll_QuizNoUsers: String { return self._s[2067]! } + public var Conversation_ViewTheme: String { return self._s[2068]! } + public var SettingsSearch_Synonyms_Privacy_Data_SecretChatLinkPreview: String { return self._s[2069]! } + public var PasscodeSettings_SimplePasscodeHelp: String { return self._s[2070]! } + public var TwoFactorSetup_Intro_Text: String { return self._s[2071]! } + public var UserInfo_GroupsInCommon: String { return self._s[2072]! } + public var TelegramWallet_Intro_TermsUrl: String { return self._s[2073]! } + public var Call_AudioRouteHide: String { return self._s[2074]! } public func Wallet_Info_TransactionDateHeader(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2070]!, self._r[2070]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2076]!, self._r[2076]!, [_1, _2]) } - public var ContactInfo_PhoneLabelMobile: String { return self._s[2071]! } - public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2072]! } - public var CreatePoll_QuizOptionsHeader: String { return self._s[2073]! } + public var ContactInfo_PhoneLabelMobile: String { return self._s[2077]! } + public var IntentsSettings_SuggestedChatsInfo: String { return self._s[2078]! } + public var CreatePoll_QuizOptionsHeader: String { return self._s[2079]! } public func ChatList_LeaveGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2074]!, self._r[2074]!, [_0]) + return formatWithArgumentRanges(self._s[2080]!, self._r[2080]!, [_0]) } - public var TextFormat_Bold: String { return self._s[2075]! } - public var FastTwoStepSetup_EmailSection: String { return self._s[2076]! } - public var StickerPackActionInfo_AddedTitle: String { return self._s[2077]! } - public var Notifications_Title: String { return self._s[2078]! } - public var Group_Username_InvalidTooShort: String { return self._s[2079]! } - public var Channel_ErrorAddTooMuch: String { return self._s[2080]! } + public var TextFormat_Bold: String { return self._s[2081]! } + public var FastTwoStepSetup_EmailSection: String { return self._s[2082]! } + public var StickerPackActionInfo_AddedTitle: String { return self._s[2083]! } + public var Notifications_Title: String { return self._s[2084]! } + public var Group_Username_InvalidTooShort: String { return self._s[2085]! } + public var Channel_ErrorAddTooMuch: String { return self._s[2086]! } public func DialogList_MultipleTypingSuffix(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2081]!, self._r[2081]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2087]!, self._r[2087]!, ["\(_0)"]) } - public var VoiceOver_DiscardPreparedContent: String { return self._s[2083]! } - public var Stickers_SuggestAdded: String { return self._s[2084]! } - public var Login_CountryCode: String { return self._s[2085]! } - public var ChatSettings_AutoPlayVideos: String { return self._s[2086]! } - public var Map_GetDirections: String { return self._s[2087]! } - public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2088]! } - public var Login_PhoneFloodError: String { return self._s[2089]! } + public var VoiceOver_DiscardPreparedContent: String { return self._s[2089]! } + public var Stickers_SuggestAdded: String { return self._s[2090]! } + public var Login_CountryCode: String { return self._s[2091]! } + public var ChatSettings_AutoPlayVideos: String { return self._s[2092]! } + public var Map_GetDirections: String { return self._s[2093]! } + public var Wallet_Receive_ShareInvoiceUrl: String { return self._s[2094]! } + public var Login_PhoneFloodError: String { return self._s[2095]! } public func Time_MonthOfYear_m3(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2090]!, self._r[2090]!, [_0]) + return formatWithArgumentRanges(self._s[2096]!, self._r[2096]!, [_0]) } public func Wallet_Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2091]!, self._r[2091]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2097]!, self._r[2097]!, [_1, _2, _3]) } - public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2092]! } - public var Settings_SetUsername: String { return self._s[2094]! } - public var Group_Location_ChangeLocation: String { return self._s[2095]! } - public var Notification_GroupInviterSelf: String { return self._s[2096]! } - public var InstantPage_TapToOpenLink: String { return self._s[2097]! } + public var IntentsSettings_SuggestedChatsPrivateChats: String { return self._s[2098]! } + public var Settings_SetUsername: String { return self._s[2100]! } + public var Group_Location_ChangeLocation: String { return self._s[2101]! } + public var Notification_GroupInviterSelf: String { return self._s[2102]! } + public var InstantPage_TapToOpenLink: String { return self._s[2103]! } public func Notification_ChannelInviter(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2098]!, self._r[2098]!, [_0]) + return formatWithArgumentRanges(self._s[2104]!, self._r[2104]!, [_0]) } - public var Watch_Suggestion_TalkLater: String { return self._s[2099]! } - public var SecretChat_Title: String { return self._s[2100]! } - public var Group_UpgradeNoticeText1: String { return self._s[2101]! } - public var AuthSessions_Title: String { return self._s[2102]! } + public var Watch_Suggestion_TalkLater: String { return self._s[2105]! } + public var SecretChat_Title: String { return self._s[2106]! } + public var Group_UpgradeNoticeText1: String { return self._s[2107]! } + public var AuthSessions_Title: String { return self._s[2108]! } public func TextFormat_AddLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2103]!, self._r[2103]!, [_0]) + return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, [_0]) } - public var PhotoEditor_CropAuto: String { return self._s[2104]! } - public var Channel_About_Title: String { return self._s[2105]! } - public var Theme_ThemeChanged: String { return self._s[2106]! } - public var FastTwoStepSetup_EmailHelp: String { return self._s[2107]! } + public var PhotoEditor_CropAuto: String { return self._s[2110]! } + public var Channel_About_Title: String { return self._s[2111]! } + public var Theme_ThemeChanged: String { return self._s[2112]! } + public var FastTwoStepSetup_EmailHelp: String { return self._s[2113]! } public func Conversation_Bytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2109]!, self._r[2109]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2115]!, self._r[2115]!, ["\(_0)"]) } - public var VoiceOver_MessageContextReport: String { return self._s[2110]! } - public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2112]! } - public var Group_Setup_HistoryVisibleHelp: String { return self._s[2113]! } + public var VoiceOver_MessageContextReport: String { return self._s[2116]! } + public var Conversation_PinMessageAlert_OnlyPin: String { return self._s[2118]! } + public var Group_Setup_HistoryVisibleHelp: String { return self._s[2119]! } public func PUSH_MESSAGE_GIF(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2114]!, self._r[2114]!, [_1]) + return formatWithArgumentRanges(self._s[2120]!, self._r[2120]!, [_1]) } public func SharedMedia_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2116]!, self._r[2116]!, [_0]) + return formatWithArgumentRanges(self._s[2122]!, self._r[2122]!, [_0]) } public func TwoStepAuth_RecoveryEmailUnavailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2117]!, self._r[2117]!, [_0]) + return formatWithArgumentRanges(self._s[2123]!, self._r[2123]!, [_0]) } - public var Privacy_PaymentsClearInfoHelp: String { return self._s[2118]! } - public var Presence_online: String { return self._s[2121]! } - public var PasscodeSettings_Title: String { return self._s[2122]! } - public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2123]! } - public var Web_OpenExternal: String { return self._s[2124]! } - public var AutoDownloadSettings_AutoDownload: String { return self._s[2126]! } - public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2127]! } - public var LocalGroup_Title: String { return self._s[2128]! } + public var Privacy_PaymentsClearInfoHelp: String { return self._s[2124]! } + public var PeopleNearby_DiscoverDescription: String { return self._s[2126]! } + public var Presence_online: String { return self._s[2128]! } + public var PasscodeSettings_Title: String { return self._s[2129]! } + public var Passport_Identity_ExpiryDatePlaceholder: String { return self._s[2130]! } + public var Web_OpenExternal: String { return self._s[2131]! } + public var AutoDownloadSettings_AutoDownload: String { return self._s[2133]! } + public var Channel_OwnershipTransfer_EnterPasswordText: String { return self._s[2134]! } + public var LocalGroup_Title: String { return self._s[2135]! } public func AutoNightTheme_AutomaticHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2129]!, self._r[2129]!, [_0]) + return formatWithArgumentRanges(self._s[2136]!, self._r[2136]!, [_0]) } - public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2130]! } - public var Conversation_StopQuizConfirmation: String { return self._s[2131]! } - public var Map_YouAreHere: String { return self._s[2132]! } + public var FastTwoStepSetup_PasswordConfirmationPlaceholder: String { return self._s[2137]! } + public var Conversation_StopQuizConfirmation: String { return self._s[2138]! } + public var Map_YouAreHere: String { return self._s[2139]! } public func AuthSessions_Message(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2133]!, self._r[2133]!, [_0]) + return formatWithArgumentRanges(self._s[2140]!, self._r[2140]!, [_0]) } public func ChatList_DeleteChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2134]!, self._r[2134]!, [_0]) + return formatWithArgumentRanges(self._s[2141]!, self._r[2141]!, [_0]) } - public var Theme_Context_ChangeColors: String { return self._s[2135]! } - public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2136]! } - public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2137]! } + public var Theme_Context_ChangeColors: String { return self._s[2142]! } + public var PrivacyLastSeenSettings_AlwaysShareWith: String { return self._s[2143]! } + public var Target_InviteToGroupErrorAlreadyInvited: String { return self._s[2144]! } public func AuthSessions_AppUnofficial(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2138]!, self._r[2138]!, [_0]) + return formatWithArgumentRanges(self._s[2145]!, self._r[2145]!, [_0]) } public func DialogList_LiveLocationSharingTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2139]!, self._r[2139]!, [_0]) + return formatWithArgumentRanges(self._s[2146]!, self._r[2146]!, [_0]) } - public var SocksProxySetup_Username: String { return self._s[2140]! } - public var Bot_Start: String { return self._s[2141]! } + public var SocksProxySetup_Username: String { return self._s[2147]! } + public var Bot_Start: String { return self._s[2148]! } public func Channel_AdminLog_EmptyFilterQueryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2142]!, self._r[2142]!, [_0]) - } - public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2143]!, self._r[2143]!, [_0]) - } - public var Contacts_SortByPresence: String { return self._s[2144]! } - public var AccentColor_Title: String { return self._s[2146]! } - public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2147]! } - public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2148]!, self._r[2148]!, [_1, _2]) - } - public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2149]!, self._r[2149]!, [_0]) } + public func Channel_AdminLog_MessagePinned(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_0]) + } + public var Contacts_SortByPresence: String { return self._s[2151]! } + public var AccentColor_Title: String { return self._s[2153]! } + public var Conversation_DiscardVoiceMessageTitle: String { return self._s[2154]! } + public func PUSH_CHAT_CREATED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2155]!, self._r[2155]!, [_1, _2]) + } + public func PrivacySettings_LastSeenContactsMinus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2156]!, self._r[2156]!, [_0]) + } public func Channel_AdminLog_MessageChangedLinkedGroup(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2150]!, self._r[2150]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2157]!, self._r[2157]!, [_1, _2]) } - public var Passport_Email_EnterOtherEmail: String { return self._s[2151]! } - public var Login_InfoAvatarPhoto: String { return self._s[2152]! } - public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2153]! } - public var Tour_Title4: String { return self._s[2154]! } - public var Passport_Identity_Translation: String { return self._s[2155]! } - public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2156]! } - public var Login_TermsOfServiceLabel: String { return self._s[2158]! } - public var Passport_Language_it: String { return self._s[2159]! } - public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2160]! } - public var Passport_Identity_SelfieHelp: String { return self._s[2161]! } - public var Conversation_ClearAll: String { return self._s[2163]! } - public var Wallet_Send_UninitializedText: String { return self._s[2165]! } - public var Channel_OwnershipTransfer_Title: String { return self._s[2166]! } - public var TwoStepAuth_FloodError: String { return self._s[2167]! } + public var Passport_Email_EnterOtherEmail: String { return self._s[2158]! } + public var Login_InfoAvatarPhoto: String { return self._s[2159]! } + public var Privacy_PaymentsClear_ShippingInfo: String { return self._s[2160]! } + public var Tour_Title4: String { return self._s[2161]! } + public var Passport_Identity_Translation: String { return self._s[2162]! } + public var SettingsSearch_Synonyms_Notifications_ContactJoined: String { return self._s[2163]! } + public var Login_TermsOfServiceLabel: String { return self._s[2165]! } + public var Passport_Language_it: String { return self._s[2166]! } + public var KeyCommand_JumpToNextUnreadChat: String { return self._s[2167]! } + public var Passport_Identity_SelfieHelp: String { return self._s[2168]! } + public var Conversation_ClearAll: String { return self._s[2170]! } + public var Wallet_Send_UninitializedText: String { return self._s[2172]! } + public var Channel_OwnershipTransfer_Title: String { return self._s[2173]! } + public var TwoStepAuth_FloodError: String { return self._s[2174]! } public func PUSH_CHANNEL_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2168]!, self._r[2168]!, [_1]) + return formatWithArgumentRanges(self._s[2175]!, self._r[2175]!, [_1]) } - public var Paint_Delete: String { return self._s[2169]! } + public var Paint_Delete: String { return self._s[2176]! } public func Wallet_Sent_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2170]!, self._r[2170]!, [_0]) + return formatWithArgumentRanges(self._s[2177]!, self._r[2177]!, [_0]) } - public var Privacy_AddNewPeer: String { return self._s[2171]! } + public var Privacy_AddNewPeer: String { return self._s[2178]! } public func Channel_AdminLog_MessageRank(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2172]!, self._r[2172]!, [_1]) + return formatWithArgumentRanges(self._s[2179]!, self._r[2179]!, [_1]) } - public var LogoutOptions_SetPasscodeText: String { return self._s[2173]! } + public var LogoutOptions_SetPasscodeText: String { return self._s[2180]! } public func Passport_AcceptHelp(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2174]!, self._r[2174]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2181]!, self._r[2181]!, [_1, _2]) } - public var Message_PinnedAudioMessage: String { return self._s[2175]! } + public var Message_PinnedAudioMessage: String { return self._s[2182]! } public func Watch_Time_ShortTodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2176]!, self._r[2176]!, [_0]) + return formatWithArgumentRanges(self._s[2183]!, self._r[2183]!, [_0]) } - public var Notification_Mute1hMin: String { return self._s[2177]! } - public var Notifications_GroupNotificationsSound: String { return self._s[2178]! } - public var Wallet_Month_GenNovember: String { return self._s[2179]! } - public var SocksProxySetup_ShareProxyList: String { return self._s[2180]! } - public var Conversation_MessageEditedLabel: String { return self._s[2181]! } + public var Notification_Mute1hMin: String { return self._s[2184]! } + public var Notifications_GroupNotificationsSound: String { return self._s[2185]! } + public var Wallet_Month_GenNovember: String { return self._s[2186]! } + public var SocksProxySetup_ShareProxyList: String { return self._s[2187]! } + public var Conversation_MessageEditedLabel: String { return self._s[2188]! } public func ClearCache_Success(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2182]!, self._r[2182]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2189]!, self._r[2189]!, [_0, _1]) } - public var Notification_Exceptions_AlwaysOff: String { return self._s[2183]! } - public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2184]! } + public var Notification_Exceptions_AlwaysOff: String { return self._s[2190]! } + public var Notification_Exceptions_NewException_MessagePreviewHeader: String { return self._s[2191]! } public func Channel_AdminLog_MessageAdmin(_ _0: String, _ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2185]!, self._r[2185]!, [_0, _1, _2]) + return formatWithArgumentRanges(self._s[2192]!, self._r[2192]!, [_0, _1, _2]) } - public var NetworkUsageSettings_ResetStats: String { return self._s[2186]! } + public var NetworkUsageSettings_ResetStats: String { return self._s[2193]! } public func PUSH_MESSAGE_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2187]!, self._r[2187]!, [_1]) + return formatWithArgumentRanges(self._s[2194]!, self._r[2194]!, [_1]) } - public var AccessDenied_LocationTracking: String { return self._s[2188]! } - public var Month_GenOctober: String { return self._s[2189]! } - public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2190]! } - public var EnterPasscode_EnterPasscode: String { return self._s[2191]! } - public var MediaPicker_TimerTooltip: String { return self._s[2193]! } - public var SharedMedia_TitleAll: String { return self._s[2194]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2197]! } - public var Conversation_RestrictedMedia: String { return self._s[2198]! } - public var AccessDenied_PhotosRestricted: String { return self._s[2199]! } - public var Privacy_Forwards_WhoCanForward: String { return self._s[2201]! } - public var ChangePhoneNumberCode_Called: String { return self._s[2202]! } + public var AccessDenied_LocationTracking: String { return self._s[2195]! } + public var Month_GenOctober: String { return self._s[2196]! } + public var GroupInfo_InviteLink_RevokeAlert_Revoke: String { return self._s[2197]! } + public var EnterPasscode_EnterPasscode: String { return self._s[2198]! } + public var MediaPicker_TimerTooltip: String { return self._s[2200]! } + public var SharedMedia_TitleAll: String { return self._s[2201]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsExceptions: String { return self._s[2204]! } + public var Conversation_RestrictedMedia: String { return self._s[2205]! } + public var AccessDenied_PhotosRestricted: String { return self._s[2206]! } + public var Privacy_Forwards_WhoCanForward: String { return self._s[2208]! } + public var ChangePhoneNumberCode_Called: String { return self._s[2209]! } public func Notification_PinnedDocumentMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2203]!, self._r[2203]!, [_0]) + return formatWithArgumentRanges(self._s[2210]!, self._r[2210]!, [_0]) } - public var Conversation_SavedMessages: String { return self._s[2206]! } - public var Your_cards_expiration_month_is_invalid: String { return self._s[2208]! } - public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2209]! } + public var Conversation_SavedMessages: String { return self._s[2213]! } + public var Your_cards_expiration_month_is_invalid: String { return self._s[2215]! } + public var FastTwoStepSetup_PasswordPlaceholder: String { return self._s[2216]! } public func Target_ShareGameConfirmationGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2211]!, self._r[2211]!, [_0]) + return formatWithArgumentRanges(self._s[2218]!, self._r[2218]!, [_0]) } - public var VoiceOver_Chat_YourMessage: String { return self._s[2212]! } + public var VoiceOver_Chat_YourMessage: String { return self._s[2219]! } public func VoiceOver_Chat_Title(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2213]!, self._r[2213]!, [_0]) + return formatWithArgumentRanges(self._s[2220]!, self._r[2220]!, [_0]) } - public var ReportPeer_AlertSuccess: String { return self._s[2214]! } - public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2215]! } + public var ReportPeer_AlertSuccess: String { return self._s[2221]! } + public var PhotoEditor_CropAspectRatioOriginal: String { return self._s[2222]! } public func InstantPage_RelatedArticleAuthorAndDateTitle(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2216]!, self._r[2216]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2223]!, self._r[2223]!, [_1, _2]) } - public var Checkout_PasswordEntry_Title: String { return self._s[2217]! } - public var PhotoEditor_FadeTool: String { return self._s[2218]! } - public var Privacy_ContactsReset: String { return self._s[2219]! } + public var Checkout_PasswordEntry_Title: String { return self._s[2224]! } + public var PhotoEditor_FadeTool: String { return self._s[2225]! } + public var Privacy_ContactsReset: String { return self._s[2226]! } public func Channel_AdminLog_MessageRestrictedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2221]!, self._r[2221]!, [_0]) + return formatWithArgumentRanges(self._s[2228]!, self._r[2228]!, [_0]) } - public var Message_PinnedVideoMessage: String { return self._s[2222]! } - public var ChatList_Mute: String { return self._s[2223]! } + public var Message_PinnedVideoMessage: String { return self._s[2229]! } + public var ChatList_Mute: String { return self._s[2230]! } public func Wallet_Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2224]!, self._r[2224]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2231]!, self._r[2231]!, [_1, _2, _3]) } - public var Permissions_CellularDataText_v0: String { return self._s[2225]! } - public var ShareMenu_SelectChats: String { return self._s[2228]! } - public var ChatList_Context_Unarchive: String { return self._s[2229]! } - public var MusicPlayer_VoiceNote: String { return self._s[2230]! } - public var Conversation_RestrictedText: String { return self._s[2231]! } - public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2232]! } - public var Wallet_Month_GenApril: String { return self._s[2233]! } - public var Wallet_Month_ShortMarch: String { return self._s[2234]! } - public var TwoStepAuth_DisableSuccess: String { return self._s[2235]! } - public var Cache_Videos: String { return self._s[2236]! } - public var PrivacySettings_PhoneNumber: String { return self._s[2237]! } - public var Wallet_Month_GenFebruary: String { return self._s[2238]! } - public var FeatureDisabled_Oops: String { return self._s[2240]! } - public var Passport_Address_PostcodePlaceholder: String { return self._s[2241]! } + public var Permissions_CellularDataText_v0: String { return self._s[2232]! } + public var ShareMenu_SelectChats: String { return self._s[2235]! } + public var ChatList_Context_Unarchive: String { return self._s[2236]! } + public var MusicPlayer_VoiceNote: String { return self._s[2237]! } + public var Conversation_RestrictedText: String { return self._s[2238]! } + public var SettingsSearch_Synonyms_Privacy_Data_DeleteDrafts: String { return self._s[2239]! } + public var Wallet_Month_GenApril: String { return self._s[2240]! } + public var Wallet_Month_ShortMarch: String { return self._s[2241]! } + public var TwoStepAuth_DisableSuccess: String { return self._s[2242]! } + public var Cache_Videos: String { return self._s[2243]! } + public var PrivacySettings_PhoneNumber: String { return self._s[2244]! } + public var Wallet_Month_GenFebruary: String { return self._s[2245]! } + public var FeatureDisabled_Oops: String { return self._s[2247]! } + public var Passport_Address_PostcodePlaceholder: String { return self._s[2248]! } public func AddContact_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2242]!, self._r[2242]!, [_0]) + return formatWithArgumentRanges(self._s[2249]!, self._r[2249]!, [_0]) } - public var Stickers_GroupStickersHelp: String { return self._s[2243]! } - public var GroupPermission_NoSendPolls: String { return self._s[2244]! } - public var Wallet_Qr_ScanCode: String { return self._s[2245]! } - public var Message_VideoExpired: String { return self._s[2247]! } - public var GroupInfo_GroupHistoryVisible: String { return self._s[2248]! } - public var Notifications_Badge: String { return self._s[2249]! } - public var Wallet_Receive_AddressCopied: String { return self._s[2250]! } - public var CreatePoll_OptionPlaceholder: String { return self._s[2251]! } - public var Username_InvalidTooShort: String { return self._s[2252]! } - public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2253]! } - public var Channel_AdminLog_PinMessages: String { return self._s[2254]! } - public var ArchivedChats_IntroTitle3: String { return self._s[2255]! } + public var Stickers_GroupStickersHelp: String { return self._s[2251]! } + public var GroupPermission_NoSendPolls: String { return self._s[2252]! } + public var Wallet_Qr_ScanCode: String { return self._s[2253]! } + public var Message_VideoExpired: String { return self._s[2255]! } + public var GroupInfo_GroupHistoryVisible: String { return self._s[2256]! } + public var Notifications_Badge: String { return self._s[2257]! } + public var Wallet_Receive_AddressCopied: String { return self._s[2258]! } + public var CreatePoll_OptionPlaceholder: String { return self._s[2259]! } + public var Username_InvalidTooShort: String { return self._s[2260]! } + public var EnterPasscode_EnterNewPasscodeChange: String { return self._s[2261]! } + public var Channel_AdminLog_PinMessages: String { return self._s[2262]! } + public var ArchivedChats_IntroTitle3: String { return self._s[2263]! } public func Notification_MessageLifetimeRemoved(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2256]!, self._r[2256]!, [_1]) + return formatWithArgumentRanges(self._s[2264]!, self._r[2264]!, [_1]) } - public var Permissions_SiriAllowInSettings_v0: String { return self._s[2257]! } - public var Conversation_DefaultRestrictedText: String { return self._s[2258]! } - public var SharedMedia_CategoryDocs: String { return self._s[2261]! } + public var Permissions_SiriAllowInSettings_v0: String { return self._s[2265]! } + public var Conversation_DefaultRestrictedText: String { return self._s[2266]! } + public var SharedMedia_CategoryDocs: String { return self._s[2269]! } public func PUSH_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2262]!, self._r[2262]!, [_1]) + return formatWithArgumentRanges(self._s[2270]!, self._r[2270]!, [_1]) } - public var Wallet_Send_UninitializedTitle: String { return self._s[2263]! } - public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2264]! } - public var Privacy_Forwards_NeverLink: String { return self._s[2266]! } + public var Wallet_Send_UninitializedTitle: String { return self._s[2271]! } + public var StickerPackActionInfo_ArchivedTitle: String { return self._s[2272]! } + public var Privacy_Forwards_NeverLink: String { return self._s[2274]! } public func Notification_MessageLifetimeChangedOutgoing(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2267]!, self._r[2267]!, [_1]) + return formatWithArgumentRanges(self._s[2275]!, self._r[2275]!, [_1]) } - public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2268]! } + public var CheckoutInfo_ErrorShippingNotAvailable: String { return self._s[2276]! } public func Time_MonthOfYear_m12(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2269]!, self._r[2269]!, [_0]) + return formatWithArgumentRanges(self._s[2277]!, self._r[2277]!, [_0]) } - public var ChatSettings_PrivateChats: String { return self._s[2270]! } - public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2271]! } - public var Conversation_PrivateMessageLinkCopied: String { return self._s[2272]! } - public var Channel_UpdatePhotoItem: String { return self._s[2273]! } - public var GroupInfo_LeftStatus: String { return self._s[2274]! } - public var Watch_MessageView_Forward: String { return self._s[2276]! } - public var ReportPeer_ReasonChildAbuse: String { return self._s[2277]! } - public var Cache_ClearEmpty: String { return self._s[2279]! } - public var Localization_LanguageName: String { return self._s[2280]! } - public var Wallet_AccessDenied_Title: String { return self._s[2281]! } - public var WebSearch_GIFs: String { return self._s[2282]! } - public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2283]! } - public var Wallet_AccessDenied_Settings: String { return self._s[2284]! } - public var Username_InvalidStartsWithNumber: String { return self._s[2285]! } - public var Common_Back: String { return self._s[2286]! } - public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2287]! } - public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2288]! } - public var Wallet_Send_Send: String { return self._s[2289]! } + public var ChatSettings_PrivateChats: String { return self._s[2278]! } + public var SettingsSearch_Synonyms_EditProfile_Logout: String { return self._s[2279]! } + public var Conversation_PrivateMessageLinkCopied: String { return self._s[2280]! } + public var Channel_UpdatePhotoItem: String { return self._s[2281]! } + public var GroupInfo_LeftStatus: String { return self._s[2282]! } + public var Watch_MessageView_Forward: String { return self._s[2284]! } + public var ReportPeer_ReasonChildAbuse: String { return self._s[2285]! } + public var Cache_ClearEmpty: String { return self._s[2287]! } + public var Localization_LanguageName: String { return self._s[2288]! } + public var Wallet_AccessDenied_Title: String { return self._s[2289]! } + public var WebSearch_GIFs: String { return self._s[2290]! } + public var Notifications_DisplayNamesOnLockScreenInfoWithLink: String { return self._s[2291]! } + public var Wallet_AccessDenied_Settings: String { return self._s[2292]! } + public var Username_InvalidStartsWithNumber: String { return self._s[2293]! } + public var Common_Back: String { return self._s[2294]! } + public var GroupInfo_Permissions_EditingDisabled: String { return self._s[2295]! } + public var Passport_Identity_DateOfBirthPlaceholder: String { return self._s[2296]! } + public var Wallet_Send_Send: String { return self._s[2297]! } public func PUSH_CHANNEL_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2291]!, self._r[2291]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2299]!, self._r[2299]!, [_1, _2]) } - public var Wallet_Info_RefreshErrorTitle: String { return self._s[2292]! } - public var Wallet_Month_GenJune: String { return self._s[2293]! } - public var Passport_Email_Help: String { return self._s[2294]! } - public var Watch_Conversation_Reply: String { return self._s[2296]! } - public var Conversation_EditingMessageMediaChange: String { return self._s[2299]! } - public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2300]! } - public var Channel_BanUser_Unban: String { return self._s[2302]! } - public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2303]! } - public var Group_Username_CreatePublicLinkHelp: String { return self._s[2304]! } - public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2306]! } - public var Wallet_Send_AddressHeader: String { return self._s[2307]! } - public var Passport_Identity_Name: String { return self._s[2308]! } + public var Wallet_Info_RefreshErrorTitle: String { return self._s[2300]! } + public var Wallet_Month_GenJune: String { return self._s[2301]! } + public var Passport_Email_Help: String { return self._s[2302]! } + public var Watch_Conversation_Reply: String { return self._s[2304]! } + public var Conversation_EditingMessageMediaChange: String { return self._s[2307]! } + public var Passport_Identity_IssueDatePlaceholder: String { return self._s[2308]! } + public var Channel_BanUser_Unban: String { return self._s[2310]! } + public var Channel_EditAdmin_PermissionPostMessages: String { return self._s[2311]! } + public var Group_Username_CreatePublicLinkHelp: String { return self._s[2312]! } + public var TwoStepAuth_ConfirmEmailCodePlaceholder: String { return self._s[2314]! } + public var Wallet_Send_AddressHeader: String { return self._s[2315]! } + public var Passport_Identity_Name: String { return self._s[2316]! } public func Channel_DiscussionGroup_HeaderGroupSet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2309]!, self._r[2309]!, [_0]) + return formatWithArgumentRanges(self._s[2317]!, self._r[2317]!, [_0]) } - public var GroupRemoved_ViewUserInfo: String { return self._s[2310]! } - public var Conversation_BlockUser: String { return self._s[2311]! } - public var Month_GenJanuary: String { return self._s[2312]! } - public var ChatSettings_TextSize: String { return self._s[2313]! } - public var Notification_PassportValuePhone: String { return self._s[2314]! } - public var MediaPlayer_UnknownArtist: String { return self._s[2315]! } - public var Passport_Language_ne: String { return self._s[2316]! } - public var Notification_CallBack: String { return self._s[2317]! } - public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2318]! } - public var TwoStepAuth_EmailHelp: String { return self._s[2319]! } + public var GroupRemoved_ViewUserInfo: String { return self._s[2318]! } + public var Conversation_BlockUser: String { return self._s[2319]! } + public var Month_GenJanuary: String { return self._s[2320]! } + public var ChatSettings_TextSize: String { return self._s[2321]! } + public var Notification_PassportValuePhone: String { return self._s[2322]! } + public var MediaPlayer_UnknownArtist: String { return self._s[2323]! } + public var Passport_Language_ne: String { return self._s[2324]! } + public var Notification_CallBack: String { return self._s[2325]! } + public var Wallet_SecureStorageReset_BiometryTouchId: String { return self._s[2326]! } + public var TwoStepAuth_EmailHelp: String { return self._s[2327]! } public func Time_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2320]!, self._r[2320]!, [_0]) + return formatWithArgumentRanges(self._s[2328]!, self._r[2328]!, [_0]) } - public var Channel_Info_Management: String { return self._s[2321]! } - public var Passport_FieldIdentityUploadHelp: String { return self._s[2322]! } - public var Stickers_FrequentlyUsed: String { return self._s[2323]! } - public var Channel_BanUser_PermissionSendMessages: String { return self._s[2324]! } - public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2326]! } + public var Channel_Info_Management: String { return self._s[2329]! } + public var Passport_FieldIdentityUploadHelp: String { return self._s[2330]! } + public var Stickers_FrequentlyUsed: String { return self._s[2331]! } + public var Channel_BanUser_PermissionSendMessages: String { return self._s[2332]! } + public var Passport_Address_OneOfTypeUtilityBill: String { return self._s[2334]! } public func LOCAL_CHANNEL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2327]!, self._r[2327]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[2335]!, self._r[2335]!, [_1, "\(_2)"]) } - public var TwoFactorSetup_Password_Title: String { return self._s[2328]! } - public var Passport_Address_EditResidentialAddress: String { return self._s[2329]! } - public var PrivacyPolicy_DeclineTitle: String { return self._s[2330]! } - public var CreatePoll_TextHeader: String { return self._s[2331]! } + public var TwoFactorSetup_Password_Title: String { return self._s[2336]! } + public var Passport_Address_EditResidentialAddress: String { return self._s[2337]! } + public var PrivacyPolicy_DeclineTitle: String { return self._s[2338]! } + public var CreatePoll_TextHeader: String { return self._s[2339]! } public func Checkout_SavePasswordTimeoutAndTouchId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2332]!, self._r[2332]!, [_0]) + return formatWithArgumentRanges(self._s[2340]!, self._r[2340]!, [_0]) } - public var PhotoEditor_QualityMedium: String { return self._s[2333]! } - public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2334]! } - public var Conversation_StatusKickedFromChannel: String { return self._s[2336]! } - public var CheckoutInfo_ReceiverInfoName: String { return self._s[2337]! } - public var Group_ErrorSendRestrictedStickers: String { return self._s[2338]! } + public var PhotoEditor_QualityMedium: String { return self._s[2341]! } + public var InfoPlist_NSMicrophoneUsageDescription: String { return self._s[2342]! } + public var Conversation_StatusKickedFromChannel: String { return self._s[2344]! } + public var CheckoutInfo_ReceiverInfoName: String { return self._s[2345]! } + public var Group_ErrorSendRestrictedStickers: String { return self._s[2346]! } public func Conversation_RestrictedInlineTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2339]!, self._r[2339]!, [_0]) + return formatWithArgumentRanges(self._s[2347]!, self._r[2347]!, [_0]) } public func Channel_AdminLog_MessageTransferedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2340]!, self._r[2340]!, [_1]) + return formatWithArgumentRanges(self._s[2348]!, self._r[2348]!, [_1]) } - public var LogoutOptions_LogOutWalletInfo: String { return self._s[2341]! } - public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2342]! } - public var Conversation_LinkDialogOpen: String { return self._s[2344]! } - public var TwoFactorSetup_Hint_Title: String { return self._s[2345]! } - public var VoiceOver_Chat_PollNoVotes: String { return self._s[2346]! } - public var Settings_Username: String { return self._s[2348]! } - public var Conversation_Block: String { return self._s[2350]! } - public var Wallpaper_Wallpaper: String { return self._s[2351]! } - public var SocksProxySetup_UseProxy: String { return self._s[2353]! } - public var Wallet_Send_Confirmation: String { return self._s[2354]! } - public var EditTheme_UploadEditedTheme: String { return self._s[2355]! } - public var UserInfo_ShareMyContactInfo: String { return self._s[2356]! } - public var MessageTimer_Forever: String { return self._s[2357]! } - public var Privacy_Calls_WhoCanCallMe: String { return self._s[2358]! } - public var PhotoEditor_DiscardChanges: String { return self._s[2359]! } - public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2360]! } - public var Passport_Language_da: String { return self._s[2361]! } - public var SocksProxySetup_PortPlaceholder: String { return self._s[2362]! } + public var LogoutOptions_LogOutWalletInfo: String { return self._s[2349]! } + public var TwoFactorSetup_Email_SkipConfirmationTitle: String { return self._s[2350]! } + public var Conversation_LinkDialogOpen: String { return self._s[2352]! } + public var TwoFactorSetup_Hint_Title: String { return self._s[2353]! } + public var VoiceOver_Chat_PollNoVotes: String { return self._s[2354]! } + public var Settings_Username: String { return self._s[2356]! } + public var Conversation_Block: String { return self._s[2358]! } + public var Wallpaper_Wallpaper: String { return self._s[2359]! } + public var SocksProxySetup_UseProxy: String { return self._s[2361]! } + public var Wallet_Send_Confirmation: String { return self._s[2362]! } + public var EditTheme_UploadEditedTheme: String { return self._s[2363]! } + public var UserInfo_ShareMyContactInfo: String { return self._s[2364]! } + public var MessageTimer_Forever: String { return self._s[2365]! } + public var Privacy_Calls_WhoCanCallMe: String { return self._s[2366]! } + public var PhotoEditor_DiscardChanges: String { return self._s[2367]! } + public var AuthSessions_TerminateOtherSessionsHelp: String { return self._s[2368]! } + public var Passport_Language_da: String { return self._s[2369]! } + public var SocksProxySetup_PortPlaceholder: String { return self._s[2370]! } public func SecretGIF_NotViewedYet(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2363]!, self._r[2363]!, [_0]) + return formatWithArgumentRanges(self._s[2371]!, self._r[2371]!, [_0]) } - public var Passport_Address_EditPassportRegistration: String { return self._s[2364]! } + public var Passport_Address_EditPassportRegistration: String { return self._s[2372]! } public func Channel_AdminLog_MessageChangedGroupAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2366]!, self._r[2366]!, [_0]) + return formatWithArgumentRanges(self._s[2374]!, self._r[2374]!, [_0]) } - public var Settings_AddDevice: String { return self._s[2367]! } - public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2369]! } - public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2370]! } - public var Conversation_SearchByName_Prefix: String { return self._s[2371]! } - public var Conversation_PinnedPoll: String { return self._s[2372]! } - public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2373]! } - public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2374]! } - public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2375]! } + public var Settings_AddDevice: String { return self._s[2375]! } + public var Passport_Identity_ResidenceCountryPlaceholder: String { return self._s[2377]! } + public var AuthSessions_AddDeviceIntro_Text1: String { return self._s[2378]! } + public var Conversation_SearchByName_Prefix: String { return self._s[2379]! } + public var Conversation_PinnedPoll: String { return self._s[2380]! } + public var AuthSessions_AddDeviceIntro_Text2: String { return self._s[2381]! } + public var Conversation_EmptyGifPanelPlaceholder: String { return self._s[2382]! } + public var AuthSessions_AddDeviceIntro_Text3: String { return self._s[2383]! } public func PUSH_ENCRYPTION_ACCEPT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2376]!, self._r[2376]!, [_1]) + return formatWithArgumentRanges(self._s[2384]!, self._r[2384]!, [_1]) } - public var WallpaperSearch_ColorPurple: String { return self._s[2377]! } - public var Cache_ByPeerHeader: String { return self._s[2378]! } + public var WallpaperSearch_ColorPurple: String { return self._s[2385]! } + public var Cache_ByPeerHeader: String { return self._s[2386]! } public func Conversation_EncryptedPlaceholderTitleIncoming(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2379]!, self._r[2379]!, [_0]) + return formatWithArgumentRanges(self._s[2387]!, self._r[2387]!, [_0]) } - public var ChatSettings_AutoDownloadDocuments: String { return self._s[2380]! } - public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2383]! } - public var Wallet_Completed_Title: String { return self._s[2384]! } - public var Notification_PinnedMessage: String { return self._s[2385]! } - public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2386]! } - public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2388]! } - public var Contacts_SortBy: String { return self._s[2389]! } + public var ChatSettings_AutoDownloadDocuments: String { return self._s[2388]! } + public var Appearance_ThemePreview_Chat_3_Text: String { return self._s[2391]! } + public var Wallet_Completed_Title: String { return self._s[2392]! } + public var Notification_PinnedMessage: String { return self._s[2393]! } + public var TwoFactorSetup_EmailVerification_Placeholder: String { return self._s[2394]! } + public var VoiceOver_Chat_RecordModeVideoMessage: String { return self._s[2396]! } + public var Contacts_SortBy: String { return self._s[2397]! } public func PUSH_CHANNEL_MESSAGE_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2390]!, self._r[2390]!, [_1]) + return formatWithArgumentRanges(self._s[2398]!, self._r[2398]!, [_1]) } - public var Appearance_ColorThemeNight: String { return self._s[2392]! } + public var Appearance_ColorThemeNight: String { return self._s[2400]! } public func PUSH_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2393]!, self._r[2393]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2401]!, self._r[2401]!, [_1, _2]) } - public var Call_EncryptionKey_Title: String { return self._s[2394]! } - public var Watch_UserInfo_Service: String { return self._s[2395]! } - public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2397]! } - public var Conversation_Unpin: String { return self._s[2399]! } - public var CancelResetAccount_Title: String { return self._s[2400]! } - public var Map_LiveLocationFor15Minutes: String { return self._s[2401]! } + public var Call_EncryptionKey_Title: String { return self._s[2402]! } + public var Watch_UserInfo_Service: String { return self._s[2403]! } + public var SettingsSearch_Synonyms_Data_SaveEditedPhotos: String { return self._s[2405]! } + public var Conversation_Unpin: String { return self._s[2407]! } + public var CancelResetAccount_Title: String { return self._s[2408]! } + public var Map_LiveLocationFor15Minutes: String { return self._s[2409]! } public func Time_PreciseDate_m8(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2403]!, self._r[2403]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2411]!, self._r[2411]!, [_1, _2, _3]) } - public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2404]! } - public var CallSettings_Title: String { return self._s[2405]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2406]! } - public var PasscodeSettings_EncryptDataHelp: String { return self._s[2408]! } - public var AutoDownloadSettings_Contacts: String { return self._s[2409]! } + public var Group_Members_AddMemberBotErrorNotAllowed: String { return self._s[2412]! } + public var CallSettings_Title: String { return self._s[2413]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground: String { return self._s[2414]! } + public var PasscodeSettings_EncryptDataHelp: String { return self._s[2416]! } + public var AutoDownloadSettings_Contacts: String { return self._s[2417]! } public func Channel_AdminLog_MessageRankName(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2410]!, self._r[2410]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2418]!, self._r[2418]!, [_1, _2]) } - public var Passport_Identity_DocumentDetails: String { return self._s[2411]! } - public var LoginPassword_PasswordHelp: String { return self._s[2412]! } - public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2413]! } - public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2414]! } - public var ChatContextMenu_TextSelectionTip: String { return self._s[2415]! } - public var Checkout_TotalPaidAmount: String { return self._s[2416]! } + public var Passport_Identity_DocumentDetails: String { return self._s[2419]! } + public var LoginPassword_PasswordHelp: String { return self._s[2420]! } + public var SettingsSearch_Synonyms_Data_AutoDownloadUsingWifi: String { return self._s[2421]! } + public var PrivacyLastSeenSettings_CustomShareSettings_Delete: String { return self._s[2422]! } + public var ChatContextMenu_TextSelectionTip: String { return self._s[2423]! } + public var Checkout_TotalPaidAmount: String { return self._s[2424]! } public func FileSize_KB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2417]!, self._r[2417]!, [_0]) + return formatWithArgumentRanges(self._s[2425]!, self._r[2425]!, [_0]) } - public var PasscodeSettings_ChangePasscode: String { return self._s[2418]! } - public var Conversation_SecretLinkPreviewAlert: String { return self._s[2420]! } - public var Privacy_SecretChatsLinkPreviews: String { return self._s[2421]! } + public var PasscodeSettings_ChangePasscode: String { return self._s[2426]! } + public var Conversation_SecretLinkPreviewAlert: String { return self._s[2428]! } + public var Privacy_SecretChatsLinkPreviews: String { return self._s[2429]! } public func PUSH_CHANNEL_MESSAGE_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2422]!, self._r[2422]!, [_1]) + return formatWithArgumentRanges(self._s[2430]!, self._r[2430]!, [_1]) } - public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2423]! } - public var Contacts_InviteFriends: String { return self._s[2425]! } - public var Map_ChooseLocationTitle: String { return self._s[2426]! } - public var Conversation_StopPoll: String { return self._s[2428]! } + public var VoiceOver_Chat_ReplyToYourMessage: String { return self._s[2431]! } + public var Contacts_InviteFriends: String { return self._s[2433]! } + public var Map_ChooseLocationTitle: String { return self._s[2434]! } + public var Conversation_StopPoll: String { return self._s[2436]! } public func WebSearch_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2429]!, self._r[2429]!, [_0]) + return formatWithArgumentRanges(self._s[2437]!, self._r[2437]!, [_0]) } - public var Call_Camera: String { return self._s[2430]! } - public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2431]! } - public var AppWallet_Intro_Text: String { return self._s[2432]! } - public var Calls_RatingFeedback: String { return self._s[2433]! } - public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2435]! } - public var Wallet_Alert_OK: String { return self._s[2436]! } - public var NotificationsSound_Pulse: String { return self._s[2437]! } - public var Watch_LastSeen_Lately: String { return self._s[2438]! } - public var ReportGroupLocation_Report: String { return self._s[2441]! } - public var Widget_NoUsers: String { return self._s[2442]! } - public var Conversation_UnvotePoll: String { return self._s[2443]! } - public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2445]! } - public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2446]! } - public var NotificationsSound_Circles: String { return self._s[2447]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2450]! } - public var Wallet_Settings_DeleteWallet: String { return self._s[2451]! } - public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2452]! } - public var Proxy_TooltipUnavailable: String { return self._s[2453]! } - public var Passport_Identity_CountryPlaceholder: String { return self._s[2455]! } - public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2457]! } - public var Conversation_FileDropbox: String { return self._s[2458]! } - public var Notifications_ExceptionsUnmuted: String { return self._s[2459]! } - public var Tour_Text3: String { return self._s[2461]! } - public var Login_ResetAccountProtected_Title: String { return self._s[2463]! } - public var GroupPermission_NoSendMessages: String { return self._s[2464]! } - public var WallpaperSearch_ColorTitle: String { return self._s[2465]! } - public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2466]! } + public var Call_Camera: String { return self._s[2438]! } + public var LogoutOptions_ChangePhoneNumberTitle: String { return self._s[2439]! } + public var AppWallet_Intro_Text: String { return self._s[2440]! } + public var Calls_RatingFeedback: String { return self._s[2441]! } + public var GroupInfo_BroadcastListNamePlaceholder: String { return self._s[2443]! } + public var Wallet_Alert_OK: String { return self._s[2444]! } + public var NotificationsSound_Pulse: String { return self._s[2445]! } + public var Watch_LastSeen_Lately: String { return self._s[2446]! } + public var ReportGroupLocation_Report: String { return self._s[2449]! } + public var Widget_NoUsers: String { return self._s[2450]! } + public var Conversation_UnvotePoll: String { return self._s[2451]! } + public var SettingsSearch_Synonyms_Privacy_ProfilePhoto: String { return self._s[2453]! } + public var Privacy_ProfilePhoto_WhoCanSeeMyPhoto: String { return self._s[2454]! } + public var NotificationsSound_Circles: String { return self._s[2455]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Title: String { return self._s[2458]! } + public var Wallet_Settings_DeleteWallet: String { return self._s[2459]! } + public var TwoStepAuth_RecoveryCodeExpired: String { return self._s[2460]! } + public var Proxy_TooltipUnavailable: String { return self._s[2461]! } + public var Passport_Identity_CountryPlaceholder: String { return self._s[2463]! } + public var GroupInfo_Permissions_SlowmodeInfo: String { return self._s[2465]! } + public var Conversation_FileDropbox: String { return self._s[2466]! } + public var Notifications_ExceptionsUnmuted: String { return self._s[2467]! } + public var Tour_Text3: String { return self._s[2469]! } + public var Login_ResetAccountProtected_Title: String { return self._s[2471]! } + public var GroupPermission_NoSendMessages: String { return self._s[2472]! } + public var WallpaperSearch_ColorTitle: String { return self._s[2473]! } + public var ChatAdmins_AllMembersAreAdminsOnHelp: String { return self._s[2474]! } public func Conversation_LiveLocationYouAnd(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2468]!, self._r[2468]!, [_0]) + return formatWithArgumentRanges(self._s[2476]!, self._r[2476]!, [_0]) } - public var GroupInfo_AddParticipantTitle: String { return self._s[2469]! } - public var Checkout_ShippingOption_Title: String { return self._s[2470]! } - public var ChatSettings_AutoDownloadTitle: String { return self._s[2471]! } + public var GroupInfo_AddParticipantTitle: String { return self._s[2477]! } + public var Checkout_ShippingOption_Title: String { return self._s[2478]! } + public var ChatSettings_AutoDownloadTitle: String { return self._s[2479]! } public func DialogList_SingleTypingSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2472]!, self._r[2472]!, [_0]) + return formatWithArgumentRanges(self._s[2480]!, self._r[2480]!, [_0]) } public func ChatSettings_AutoDownloadSettings_TypeVideo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2473]!, self._r[2473]!, [_0]) + return formatWithArgumentRanges(self._s[2481]!, self._r[2481]!, [_0]) } - public var Channel_Management_LabelAdministrator: String { return self._s[2474]! } - public var EditTheme_FileReadError: String { return self._s[2475]! } - public var OwnershipTransfer_ComeBackLater: String { return self._s[2476]! } - public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2477]! } - public var AutoDownloadSettings_Photos: String { return self._s[2479]! } - public var Appearance_PreviewIncomingText: String { return self._s[2480]! } - public var ChatList_Context_MarkAllAsRead: String { return self._s[2481]! } - public var ChannelInfo_ConfirmLeave: String { return self._s[2482]! } - public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2483]! } - public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2484]! } - public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2485]! } - public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2486]! } - public var GroupInfo_SetGroupPhotoStop: String { return self._s[2487]! } - public var Notification_SecretChatScreenshot: String { return self._s[2488]! } - public var AccessDenied_Wallpapers: String { return self._s[2489]! } - public var ChatList_Context_Mute: String { return self._s[2491]! } - public var Passport_Address_City: String { return self._s[2492]! } - public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2493]! } - public var Appearance_ThemeCarouselClassic: String { return self._s[2494]! } - public var SocksProxySetup_SecretPlaceholder: String { return self._s[2495]! } - public var AccessDenied_LocationDisabled: String { return self._s[2496]! } - public var Group_Location_Title: String { return self._s[2497]! } - public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2499]! } - public var GroupInfo_Sound: String { return self._s[2500]! } - public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2501]! } - public var ChannelInfo_ScamChannelWarning: String { return self._s[2502]! } - public var Stickers_RemoveFromFavorites: String { return self._s[2503]! } - public var Contacts_Title: String { return self._s[2504]! } - public var EditTheme_ThemeTemplateAlertText: String { return self._s[2505]! } - public var Passport_Language_fr: String { return self._s[2506]! } - public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2507]! } - public var Notifications_ResetAllNotifications: String { return self._s[2508]! } - public var IntentsSettings_SuggestedChats: String { return self._s[2510]! } - public var PrivacySettings_SecurityTitle: String { return self._s[2512]! } - public var Checkout_NewCard_Title: String { return self._s[2513]! } - public var Login_HaveNotReceivedCodeInternal: String { return self._s[2514]! } - public var Conversation_ForwardChats: String { return self._s[2515]! } - public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2517]! } - public var PasscodeSettings_4DigitCode: String { return self._s[2518]! } - public var Settings_FAQ: String { return self._s[2520]! } - public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2521]! } - public var Conversation_ContextMenuForward: String { return self._s[2522]! } - public var VoiceOver_Chat_YourPhoto: String { return self._s[2525]! } - public var PrivacyPolicy_Title: String { return self._s[2528]! } - public var Notifications_TextTone: String { return self._s[2529]! } - public var Profile_CreateNewContact: String { return self._s[2530]! } - public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2531]! } - public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2533]! } - public var Call_Speaker: String { return self._s[2534]! } - public var AutoNightTheme_AutomaticSection: String { return self._s[2535]! } - public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2537]! } - public var Channel_Username_InvalidCharacters: String { return self._s[2538]! } + public var Channel_Management_LabelAdministrator: String { return self._s[2482]! } + public var EditTheme_FileReadError: String { return self._s[2483]! } + public var OwnershipTransfer_ComeBackLater: String { return self._s[2484]! } + public var PrivacyLastSeenSettings_NeverShareWith_Placeholder: String { return self._s[2485]! } + public var AutoDownloadSettings_Photos: String { return self._s[2487]! } + public var Appearance_PreviewIncomingText: String { return self._s[2488]! } + public var ChatList_Context_MarkAllAsRead: String { return self._s[2489]! } + public var ChannelInfo_ConfirmLeave: String { return self._s[2490]! } + public var MediaPicker_MomentsDateRangeSameMonthYearFormat: String { return self._s[2491]! } + public var Passport_Identity_DocumentNumberPlaceholder: String { return self._s[2492]! } + public var Channel_AdminLogFilter_EventsNewMembers: String { return self._s[2493]! } + public var PasscodeSettings_AutoLock_IfAwayFor_5minutes: String { return self._s[2494]! } + public var GroupInfo_SetGroupPhotoStop: String { return self._s[2495]! } + public var Notification_SecretChatScreenshot: String { return self._s[2496]! } + public var AccessDenied_Wallpapers: String { return self._s[2497]! } + public var ChatList_Context_Mute: String { return self._s[2499]! } + public var Passport_Address_City: String { return self._s[2500]! } + public var InfoPlist_NSPhotoLibraryAddUsageDescription: String { return self._s[2501]! } + public var Appearance_ThemeCarouselClassic: String { return self._s[2502]! } + public var SocksProxySetup_SecretPlaceholder: String { return self._s[2503]! } + public var AccessDenied_LocationDisabled: String { return self._s[2504]! } + public var Group_Location_Title: String { return self._s[2505]! } + public var SocksProxySetup_HostnamePlaceholder: String { return self._s[2507]! } + public var GroupInfo_Sound: String { return self._s[2508]! } + public var SettingsSearch_Synonyms_ChatSettings_OpenLinksIn: String { return self._s[2509]! } + public var ChannelInfo_ScamChannelWarning: String { return self._s[2510]! } + public var Stickers_RemoveFromFavorites: String { return self._s[2511]! } + public var Contacts_Title: String { return self._s[2512]! } + public var EditTheme_ThemeTemplateAlertText: String { return self._s[2513]! } + public var Passport_Language_fr: String { return self._s[2514]! } + public var TwoFactorSetup_EmailVerification_Action: String { return self._s[2515]! } + public var Notifications_ResetAllNotifications: String { return self._s[2516]! } + public var IntentsSettings_SuggestedChats: String { return self._s[2518]! } + public var PrivacySettings_SecurityTitle: String { return self._s[2520]! } + public var Checkout_NewCard_Title: String { return self._s[2521]! } + public var Login_HaveNotReceivedCodeInternal: String { return self._s[2522]! } + public var Conversation_ForwardChats: String { return self._s[2523]! } + public var Wallet_SecureStorageReset_PasscodeText: String { return self._s[2525]! } + public var PasscodeSettings_4DigitCode: String { return self._s[2526]! } + public var Settings_FAQ: String { return self._s[2528]! } + public var AutoDownloadSettings_DocumentsTitle: String { return self._s[2529]! } + public var Conversation_ContextMenuForward: String { return self._s[2530]! } + public var VoiceOver_Chat_YourPhoto: String { return self._s[2533]! } + public var PrivacyPolicy_Title: String { return self._s[2536]! } + public var Notifications_TextTone: String { return self._s[2537]! } + public var Profile_CreateNewContact: String { return self._s[2538]! } + public var PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber: String { return self._s[2539]! } + public var TwoFactorSetup_EmailVerification_Title: String { return self._s[2541]! } + public var Call_Speaker: String { return self._s[2542]! } + public var AutoNightTheme_AutomaticSection: String { return self._s[2543]! } + public var Channel_OwnershipTransfer_EnterPassword: String { return self._s[2545]! } + public var Channel_Username_InvalidCharacters: String { return self._s[2546]! } public func Channel_AdminLog_MessageChangedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2539]!, self._r[2539]!, [_0]) + return formatWithArgumentRanges(self._s[2547]!, self._r[2547]!, [_0]) } - public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2540]! } - public var PrivacySettings_LastSeenTitle: String { return self._s[2541]! } - public var Channel_AdminLog_CanInviteUsers: String { return self._s[2542]! } - public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2543]! } - public var OwnershipTransfer_SecurityCheck: String { return self._s[2544]! } - public var Conversation_MessageDeliveryFailed: String { return self._s[2545]! } - public var Watch_ChatList_NoConversationsText: String { return self._s[2546]! } - public var Bot_Unblock: String { return self._s[2547]! } - public var TextFormat_Italic: String { return self._s[2548]! } - public var WallpaperSearch_ColorPink: String { return self._s[2549]! } - public var Settings_About_Help: String { return self._s[2551]! } - public var SearchImages_Title: String { return self._s[2552]! } - public var Weekday_Wednesday: String { return self._s[2553]! } - public var Conversation_ClousStorageInfo_Description1: String { return self._s[2554]! } - public var ExplicitContent_AlertTitle: String { return self._s[2555]! } + public var AutoDownloadSettings_AutodownloadFiles: String { return self._s[2548]! } + public var PrivacySettings_LastSeenTitle: String { return self._s[2549]! } + public var Channel_AdminLog_CanInviteUsers: String { return self._s[2550]! } + public var SettingsSearch_Synonyms_Privacy_Data_ClearPaymentsInfo: String { return self._s[2551]! } + public var OwnershipTransfer_SecurityCheck: String { return self._s[2552]! } + public var Conversation_MessageDeliveryFailed: String { return self._s[2553]! } + public var Watch_ChatList_NoConversationsText: String { return self._s[2554]! } + public var Bot_Unblock: String { return self._s[2555]! } + public var TextFormat_Italic: String { return self._s[2556]! } + public var WallpaperSearch_ColorPink: String { return self._s[2557]! } + public var Settings_About_Help: String { return self._s[2559]! } + public var SearchImages_Title: String { return self._s[2560]! } + public var Weekday_Wednesday: String { return self._s[2561]! } + public var Conversation_ClousStorageInfo_Description1: String { return self._s[2562]! } + public var ExplicitContent_AlertTitle: String { return self._s[2563]! } public func Time_PreciseDate_m5(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2556]!, self._r[2556]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2564]!, self._r[2564]!, [_1, _2, _3]) } - public var Channel_DiscussionGroup_Create: String { return self._s[2557]! } - public var Weekday_Thursday: String { return self._s[2558]! } - public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2559]! } - public var Channel_Members_AddMembersHelp: String { return self._s[2560]! } + public var Channel_DiscussionGroup_Create: String { return self._s[2565]! } + public var Weekday_Thursday: String { return self._s[2566]! } + public var Channel_BanUser_PermissionChangeGroupInfo: String { return self._s[2567]! } + public var Channel_Members_AddMembersHelp: String { return self._s[2568]! } public func Checkout_SavePasswordTimeout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2561]!, self._r[2561]!, [_0]) + return formatWithArgumentRanges(self._s[2569]!, self._r[2569]!, [_0]) } - public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2562]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2563]! } - public var Passport_RequestedInformation: String { return self._s[2564]! } - public var Login_PhoneAndCountryHelp: String { return self._s[2565]! } - public var Conversation_EncryptionProcessing: String { return self._s[2567]! } - public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2568]! } - public var PhotoEditor_EnhanceTool: String { return self._s[2570]! } - public var Channel_Setup_Title: String { return self._s[2571]! } - public var Conversation_SearchPlaceholder: String { return self._s[2572]! } - public var OldChannels_GroupEmptyFormat: String { return self._s[2573]! } - public var AccessDenied_LocationAlwaysDenied: String { return self._s[2574]! } - public var Checkout_ErrorGeneric: String { return self._s[2575]! } - public var Passport_Language_hu: String { return self._s[2576]! } - public var GroupPermission_EditingDisabled: String { return self._s[2577]! } - public var Wallet_Month_ShortSeptember: String { return self._s[2579]! } + public var Channel_DiscussionGroup_LinkGroup: String { return self._s[2570]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsVibrate: String { return self._s[2571]! } + public var Passport_RequestedInformation: String { return self._s[2572]! } + public var Login_PhoneAndCountryHelp: String { return self._s[2573]! } + public var Conversation_EncryptionProcessing: String { return self._s[2575]! } + public var Notifications_PermissionsSuppressWarningTitle: String { return self._s[2576]! } + public var PhotoEditor_EnhanceTool: String { return self._s[2578]! } + public var Channel_Setup_Title: String { return self._s[2579]! } + public var Conversation_SearchPlaceholder: String { return self._s[2580]! } + public var OldChannels_GroupEmptyFormat: String { return self._s[2581]! } + public var AccessDenied_LocationAlwaysDenied: String { return self._s[2582]! } + public var Checkout_ErrorGeneric: String { return self._s[2583]! } + public var Passport_Language_hu: String { return self._s[2584]! } + public var GroupPermission_EditingDisabled: String { return self._s[2585]! } + public var Wallet_Month_ShortSeptember: String { return self._s[2587]! } public func Passport_Identity_UploadOneOfScan(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2580]!, self._r[2580]!, [_0]) + return formatWithArgumentRanges(self._s[2588]!, self._r[2588]!, [_0]) } public func PUSH_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2583]!, self._r[2583]!, [_1]) + return formatWithArgumentRanges(self._s[2591]!, self._r[2591]!, [_1]) } - public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2584]! } + public var ChatList_DeleteSavedMessagesConfirmationTitle: String { return self._s[2592]! } public func UserInfo_BlockConfirmationTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2585]!, self._r[2585]!, [_0]) + return formatWithArgumentRanges(self._s[2593]!, self._r[2593]!, [_0]) } - public var Conversation_CloudStorageInfo_Title: String { return self._s[2586]! } - public var Group_Location_Info: String { return self._s[2587]! } - public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2588]! } - public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2589]! } + public var Conversation_CloudStorageInfo_Title: String { return self._s[2594]! } + public var Group_Location_Info: String { return self._s[2595]! } + public var PhotoEditor_CropAspectRatioSquare: String { return self._s[2596]! } + public var Permissions_PeopleNearbyAllow_v0: String { return self._s[2597]! } public func Notification_Exceptions_MutedUntil(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2590]!, self._r[2590]!, [_0]) + return formatWithArgumentRanges(self._s[2598]!, self._r[2598]!, [_0]) } - public var Conversation_ClearPrivateHistory: String { return self._s[2591]! } - public var ContactInfo_PhoneLabelHome: String { return self._s[2592]! } - public var Appearance_RemoveThemeConfirmation: String { return self._s[2593]! } - public var PrivacySettings_LastSeenContacts: String { return self._s[2594]! } + public var Conversation_ClearPrivateHistory: String { return self._s[2599]! } + public var ContactInfo_PhoneLabelHome: String { return self._s[2600]! } + public var Appearance_RemoveThemeConfirmation: String { return self._s[2601]! } + public var PrivacySettings_LastSeenContacts: String { return self._s[2602]! } public func ChangePhone_ErrorOccupied(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2595]!, self._r[2595]!, [_0]) + return formatWithArgumentRanges(self._s[2603]!, self._r[2603]!, [_0]) } - public var Passport_Language_cs: String { return self._s[2596]! } - public var Message_PinnedAnimationMessage: String { return self._s[2598]! } - public var Passport_Identity_ReverseSideHelp: String { return self._s[2600]! } - public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2601]! } - public var Wallet_Info_TransactionTo: String { return self._s[2603]! } - public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2604]! } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2605]! } - public var Embed_PlayingInPIP: String { return self._s[2606]! } - public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2607]! } - public var AutoNightTheme_ScheduleSection: String { return self._s[2608]! } + public var Passport_Language_cs: String { return self._s[2604]! } + public var Message_PinnedAnimationMessage: String { return self._s[2606]! } + public var Passport_Identity_ReverseSideHelp: String { return self._s[2608]! } + public var SettingsSearch_Synonyms_Data_Storage_Title: String { return self._s[2609]! } + public var Wallet_Info_TransactionTo: String { return self._s[2611]! } + public var ChatList_DeleteForEveryoneConfirmationText: String { return self._s[2612]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndTouchId: String { return self._s[2613]! } + public var Embed_PlayingInPIP: String { return self._s[2614]! } + public var Appearance_ThemePreview_Chat_3_TextWithLink: String { return self._s[2615]! } + public var AutoNightTheme_ScheduleSection: String { return self._s[2616]! } public func Call_EmojiDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2609]!, self._r[2609]!, [_0]) + return formatWithArgumentRanges(self._s[2617]!, self._r[2617]!, [_0]) } - public var MediaPicker_LivePhotoDescription: String { return self._s[2610]! } + public var MediaPicker_LivePhotoDescription: String { return self._s[2618]! } public func Channel_AdminLog_MessageRestrictedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2611]!, self._r[2611]!, [_1]) + return formatWithArgumentRanges(self._s[2619]!, self._r[2619]!, [_1]) } - public var Notification_PaymentSent: String { return self._s[2612]! } - public var PhotoEditor_CurvesGreen: String { return self._s[2613]! } - public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2614]! } - public var AutoNightTheme_System: String { return self._s[2615]! } - public var SaveIncomingPhotosSettings_Title: String { return self._s[2616]! } - public var CreatePoll_QuizTitle: String { return self._s[2617]! } - public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2618]! } - public var VoiceOver_Chat_PagePreview: String { return self._s[2619]! } + public var Notification_PaymentSent: String { return self._s[2620]! } + public var PhotoEditor_CurvesGreen: String { return self._s[2621]! } + public var Notification_Exceptions_PreviewAlwaysOff: String { return self._s[2622]! } + public var AutoNightTheme_System: String { return self._s[2623]! } + public var SaveIncomingPhotosSettings_Title: String { return self._s[2624]! } + public var CreatePoll_QuizTitle: String { return self._s[2625]! } + public var NotificationSettings_ShowNotificationsAllAccounts: String { return self._s[2626]! } + public var VoiceOver_Chat_PagePreview: String { return self._s[2627]! } public func PUSH_MESSAGE_SCREENSHOT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2622]!, self._r[2622]!, [_1]) + return formatWithArgumentRanges(self._s[2630]!, self._r[2630]!, [_1]) } public func PUSH_MESSAGE_PHOTO_SECRET(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2623]!, self._r[2623]!, [_1]) + return formatWithArgumentRanges(self._s[2631]!, self._r[2631]!, [_1]) } public func ApplyLanguage_UnsufficientDataText(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2624]!, self._r[2624]!, [_1]) + return formatWithArgumentRanges(self._s[2632]!, self._r[2632]!, [_1]) } - public var NetworkUsageSettings_CallDataSection: String { return self._s[2626]! } - public var PasscodeSettings_HelpTop: String { return self._s[2627]! } - public var Conversation_WalletRequiredTitle: String { return self._s[2628]! } - public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2629]! } - public var Passport_Address_TypeRentalAgreement: String { return self._s[2630]! } - public var EditTheme_ShortLink: String { return self._s[2631]! } - public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2632]! } - public var ProxyServer_VoiceOver_Active: String { return self._s[2633]! } - public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2634]! } - public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2635]! } - public var Call_Accept: String { return self._s[2637]! } - public var GroupRemoved_RemoveInfo: String { return self._s[2638]! } - public var Month_GenMarch: String { return self._s[2640]! } - public var PhotoEditor_ShadowsTool: String { return self._s[2641]! } - public var LoginPassword_Title: String { return self._s[2642]! } - public var Call_End: String { return self._s[2643]! } - public var Watch_Conversation_GroupInfo: String { return self._s[2644]! } - public var VoiceOver_Chat_Contact: String { return self._s[2645]! } - public var EditTheme_Create_Preview_IncomingText: String { return self._s[2646]! } - public var CallSettings_Always: String { return self._s[2647]! } - public var CallFeedback_Success: String { return self._s[2648]! } - public var TwoStepAuth_SetupHint: String { return self._s[2649]! } + public var NetworkUsageSettings_CallDataSection: String { return self._s[2634]! } + public var PasscodeSettings_HelpTop: String { return self._s[2635]! } + public var Conversation_WalletRequiredTitle: String { return self._s[2636]! } + public var Group_OwnershipTransfer_ErrorAdminsTooMuch: String { return self._s[2637]! } + public var Passport_Address_TypeRentalAgreement: String { return self._s[2638]! } + public var EditTheme_ShortLink: String { return self._s[2639]! } + public var Theme_Colors_ColorWallpaperWarning: String { return self._s[2640]! } + public var ProxyServer_VoiceOver_Active: String { return self._s[2641]! } + public var ReportPeer_ReasonOther_Placeholder: String { return self._s[2642]! } + public var CheckoutInfo_ErrorPhoneInvalid: String { return self._s[2643]! } + public var Call_Accept: String { return self._s[2645]! } + public var GroupRemoved_RemoveInfo: String { return self._s[2646]! } + public var Month_GenMarch: String { return self._s[2648]! } + public var PhotoEditor_ShadowsTool: String { return self._s[2649]! } + public var LoginPassword_Title: String { return self._s[2650]! } + public var Call_End: String { return self._s[2651]! } + public var Watch_Conversation_GroupInfo: String { return self._s[2652]! } + public var VoiceOver_Chat_Contact: String { return self._s[2653]! } + public var EditTheme_Create_Preview_IncomingText: String { return self._s[2654]! } + public var CallSettings_Always: String { return self._s[2655]! } + public var CallFeedback_Success: String { return self._s[2656]! } + public var TwoStepAuth_SetupHint: String { return self._s[2657]! } public func AddContact_ContactWillBeSharedAfterMutual(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2650]!, self._r[2650]!, [_1]) + return formatWithArgumentRanges(self._s[2658]!, self._r[2658]!, [_1]) } - public var ConversationProfile_UsersTooMuchError: String { return self._s[2651]! } - public var Login_PhoneTitle: String { return self._s[2652]! } - public var Passport_FieldPhoneHelp: String { return self._s[2653]! } - public var Weekday_ShortSunday: String { return self._s[2654]! } - public var Passport_InfoFAQ_URL: String { return self._s[2655]! } - public var ContactInfo_Job: String { return self._s[2657]! } - public var UserInfo_InviteBotToGroup: String { return self._s[2658]! } - public var Appearance_ThemeCarouselNightBlue: String { return self._s[2659]! } - public var CreatePoll_QuizTip: String { return self._s[2660]! } - public var TwoFactorSetup_Email_Text: String { return self._s[2661]! } - public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2662]! } - public var Invite_ChannelsTooMuch: String { return self._s[2663]! } - public var Wallet_Send_ConfirmationConfirm: String { return self._s[2664]! } - public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2665]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2666]! } - public var Wallet_Receive_AmountText: String { return self._s[2667]! } - public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2668]! } - public var CallFeedback_ReasonNoise: String { return self._s[2669]! } - public var Appearance_AppIconDefault: String { return self._s[2671]! } - public var Passport_Identity_AddInternalPassport: String { return self._s[2672]! } - public var MediaPicker_AddCaption: String { return self._s[2673]! } - public var CallSettings_TabIconDescription: String { return self._s[2674]! } + public var ConversationProfile_UsersTooMuchError: String { return self._s[2659]! } + public var Login_PhoneTitle: String { return self._s[2660]! } + public var Passport_FieldPhoneHelp: String { return self._s[2661]! } + public var Weekday_ShortSunday: String { return self._s[2662]! } + public var Passport_InfoFAQ_URL: String { return self._s[2663]! } + public var ContactInfo_Job: String { return self._s[2665]! } + public var UserInfo_InviteBotToGroup: String { return self._s[2666]! } + public var Appearance_ThemeCarouselNightBlue: String { return self._s[2667]! } + public var CreatePoll_QuizTip: String { return self._s[2668]! } + public var TwoFactorSetup_Email_Text: String { return self._s[2669]! } + public var TwoStepAuth_PasswordRemovePassportConfirmation: String { return self._s[2670]! } + public var Invite_ChannelsTooMuch: String { return self._s[2671]! } + public var Wallet_Send_ConfirmationConfirm: String { return self._s[2672]! } + public var Wallet_TransactionInfo_OtherFeeInfo: String { return self._s[2673]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsPreview: String { return self._s[2674]! } + public var Wallet_Receive_AmountText: String { return self._s[2675]! } + public var Passport_DeletePersonalDetailsConfirmation: String { return self._s[2676]! } + public var CallFeedback_ReasonNoise: String { return self._s[2677]! } + public var Appearance_AppIconDefault: String { return self._s[2679]! } + public var Passport_Identity_AddInternalPassport: String { return self._s[2680]! } + public var MediaPicker_AddCaption: String { return self._s[2681]! } + public var CallSettings_TabIconDescription: String { return self._s[2682]! } public func VoiceOver_Chat_Caption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2675]!, self._r[2675]!, [_0]) + return formatWithArgumentRanges(self._s[2683]!, self._r[2683]!, [_0]) } - public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2676]! } + public var IntentsSettings_SuggestedChatsGroups: String { return self._s[2684]! } public func Map_SearchNoResultsDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2677]!, self._r[2677]!, [_0]) + return formatWithArgumentRanges(self._s[2685]!, self._r[2685]!, [_0]) } - public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2678]! } - public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2679]! } - public var Passport_Identity_TypePersonalDetails: String { return self._s[2680]! } - public var DialogList_SearchSectionRecent: String { return self._s[2681]! } - public var PrivacyPolicy_DeclineMessage: String { return self._s[2682]! } - public var CreatePoll_Anonymous: String { return self._s[2683]! } - public var LogoutOptions_ClearCacheText: String { return self._s[2686]! } - public var LastSeen_WithinAWeek: String { return self._s[2687]! } - public var ChannelMembers_GroupAdminsTitle: String { return self._s[2688]! } - public var Conversation_CloudStorage_ChatStatus: String { return self._s[2690]! } - public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2691]! } + public var ChatList_UndoArchiveHiddenTitle: String { return self._s[2686]! } + public var Privacy_GroupsAndChannels_AlwaysAllow: String { return self._s[2687]! } + public var Passport_Identity_TypePersonalDetails: String { return self._s[2688]! } + public var DialogList_SearchSectionRecent: String { return self._s[2689]! } + public var PrivacyPolicy_DeclineMessage: String { return self._s[2690]! } + public var CreatePoll_Anonymous: String { return self._s[2691]! } + public var LogoutOptions_ClearCacheText: String { return self._s[2694]! } + public var LastSeen_WithinAWeek: String { return self._s[2695]! } + public var ChannelMembers_GroupAdminsTitle: String { return self._s[2696]! } + public var Conversation_CloudStorage_ChatStatus: String { return self._s[2698]! } + public var VoiceOver_Media_PlaybackRateNormal: String { return self._s[2699]! } public func AddContact_SharedContactExceptionInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2692]!, self._r[2692]!, [_0]) + return formatWithArgumentRanges(self._s[2700]!, self._r[2700]!, [_0]) } - public var Passport_Address_TypeResidentialAddress: String { return self._s[2693]! } - public var Conversation_StatusLeftGroup: String { return self._s[2694]! } - public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2695]! } - public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2697]! } - public var GroupPermission_AddSuccess: String { return self._s[2698]! } - public var PhotoEditor_BlurToolRadial: String { return self._s[2700]! } - public var Conversation_ContextMenuCopy: String { return self._s[2701]! } - public var AccessDenied_CallMicrophone: String { return self._s[2702]! } + public var Passport_Address_TypeResidentialAddress: String { return self._s[2701]! } + public var Conversation_StatusLeftGroup: String { return self._s[2702]! } + public var SocksProxySetup_ProxyDetailsTitle: String { return self._s[2703]! } + public var SettingsSearch_Synonyms_Calls_Title: String { return self._s[2705]! } + public var GroupPermission_AddSuccess: String { return self._s[2706]! } + public var PhotoEditor_BlurToolRadial: String { return self._s[2708]! } + public var Conversation_ContextMenuCopy: String { return self._s[2709]! } + public var AccessDenied_CallMicrophone: String { return self._s[2710]! } public func Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2703]!, self._r[2703]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2711]!, self._r[2711]!, [_1, _2, _3]) } - public var Login_InvalidFirstNameError: String { return self._s[2704]! } - public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2705]! } - public var Checkout_PaymentMethod_New: String { return self._s[2706]! } - public var ShareMenu_CopyShareLinkGame: String { return self._s[2707]! } - public var PhotoEditor_QualityTool: String { return self._s[2708]! } - public var Login_SendCodeViaSms: String { return self._s[2709]! } - public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2710]! } - public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2711]! } - public var Wallet_Receive_CopyAddress: String { return self._s[2712]! } - public var Login_EmailNotConfiguredError: String { return self._s[2713]! } - public var SocksProxySetup_Status: String { return self._s[2714]! } - public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2715]! } - public var PrivacyPolicy_Accept: String { return self._s[2716]! } - public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2717]! } - public var Appearance_AppIconClassicX: String { return self._s[2718]! } + public var Login_InvalidFirstNameError: String { return self._s[2712]! } + public var Notifications_Badge_CountUnreadMessages_InfoOn: String { return self._s[2713]! } + public var Checkout_PaymentMethod_New: String { return self._s[2714]! } + public var ShareMenu_CopyShareLinkGame: String { return self._s[2715]! } + public var PhotoEditor_QualityTool: String { return self._s[2716]! } + public var Login_SendCodeViaSms: String { return self._s[2717]! } + public var SettingsSearch_Synonyms_Privacy_DeleteAccountIfAwayFor: String { return self._s[2718]! } + public var Chat_SlowmodeAttachmentLimitReached: String { return self._s[2719]! } + public var Wallet_Receive_CopyAddress: String { return self._s[2720]! } + public var Login_EmailNotConfiguredError: String { return self._s[2721]! } + public var SocksProxySetup_Status: String { return self._s[2722]! } + public var Conversation_ScheduleMessage_SendWhenOnline: String { return self._s[2723]! } + public var PrivacyPolicy_Accept: String { return self._s[2724]! } + public var Notifications_ExceptionsMessagePlaceholder: String { return self._s[2725]! } + public var Appearance_AppIconClassicX: String { return self._s[2726]! } public func PUSH_CHAT_MESSAGE_TEXT(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2719]!, self._r[2719]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2727]!, self._r[2727]!, [_1, _2, _3]) } - public var OwnershipTransfer_SecurityRequirements: String { return self._s[2720]! } - public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2722]! } - public var AutoNightTheme_Automatic: String { return self._s[2723]! } - public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2724]! } - public var Privacy_ContactsSyncHelp: String { return self._s[2725]! } - public var Cache_Help: String { return self._s[2726]! } - public var Group_ErrorAccessDenied: String { return self._s[2727]! } - public var Passport_Language_fa: String { return self._s[2728]! } - public var Wallet_Intro_Text: String { return self._s[2729]! } - public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2730]! } - public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2731]! } - public var PrivacySettings_LastSeen: String { return self._s[2732]! } + public var OwnershipTransfer_SecurityRequirements: String { return self._s[2728]! } + public var InfoPlist_NSLocationAlwaysUsageDescription: String { return self._s[2730]! } + public var AutoNightTheme_Automatic: String { return self._s[2731]! } + public var Channel_Username_InvalidStartsWithNumber: String { return self._s[2732]! } + public var Privacy_ContactsSyncHelp: String { return self._s[2733]! } + public var Cache_Help: String { return self._s[2734]! } + public var Group_ErrorAccessDenied: String { return self._s[2735]! } + public var Passport_Language_fa: String { return self._s[2736]! } + public var Wallet_Intro_Text: String { return self._s[2737]! } + public var Login_ResetAccountProtected_TimerTitle: String { return self._s[2738]! } + public var VoiceOver_Chat_YourVideoMessage: String { return self._s[2739]! } + public var PrivacySettings_LastSeen: String { return self._s[2740]! } public func DialogList_MultipleTyping(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2733]!, self._r[2733]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2741]!, self._r[2741]!, [_0, _1]) } - public var Wallet_Configuration_Apply: String { return self._s[2737]! } - public var Preview_SaveGif: String { return self._s[2738]! } - public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2739]! } - public var Profile_About: String { return self._s[2740]! } - public var Channel_About_Placeholder: String { return self._s[2741]! } - public var Login_InfoTitle: String { return self._s[2742]! } + public var Wallet_Configuration_Apply: String { return self._s[2745]! } + public var Preview_SaveGif: String { return self._s[2746]! } + public var SettingsSearch_Synonyms_Privacy_TwoStepAuth: String { return self._s[2747]! } + public var Profile_About: String { return self._s[2748]! } + public var Channel_About_Placeholder: String { return self._s[2749]! } + public var Login_InfoTitle: String { return self._s[2750]! } public func TwoStepAuth_SetupPendingEmail(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2743]!, self._r[2743]!, [_0]) + return formatWithArgumentRanges(self._s[2751]!, self._r[2751]!, [_0]) } - public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2744]! } - public var Watch_Suggestion_CantTalk: String { return self._s[2746]! } - public var ContactInfo_Title: String { return self._s[2747]! } - public var Media_ShareThisVideo: String { return self._s[2748]! } - public var Weekday_ShortFriday: String { return self._s[2749]! } - public var AccessDenied_Contacts: String { return self._s[2751]! } - public var Notification_CallIncomingShort: String { return self._s[2752]! } - public var Group_Setup_TypePublic: String { return self._s[2753]! } - public var Notifications_MessageNotificationsExceptions: String { return self._s[2754]! } - public var Notifications_Badge_IncludeChannels: String { return self._s[2755]! } - public var Notifications_MessageNotificationsPreview: String { return self._s[2758]! } - public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2759]! } - public var Group_ErrorAddTooMuchBots: String { return self._s[2760]! } - public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2761]! } - public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2762]! } + public var EditTheme_Expand_Preview_IncomingReplyText: String { return self._s[2752]! } + public var Watch_Suggestion_CantTalk: String { return self._s[2754]! } + public var ContactInfo_Title: String { return self._s[2755]! } + public var Media_ShareThisVideo: String { return self._s[2756]! } + public var Weekday_ShortFriday: String { return self._s[2757]! } + public var AccessDenied_Contacts: String { return self._s[2759]! } + public var Notification_CallIncomingShort: String { return self._s[2760]! } + public var Group_Setup_TypePublic: String { return self._s[2761]! } + public var Notifications_MessageNotificationsExceptions: String { return self._s[2762]! } + public var Notifications_Badge_IncludeChannels: String { return self._s[2763]! } + public var Notifications_MessageNotificationsPreview: String { return self._s[2766]! } + public var ConversationProfile_ErrorCreatingConversation: String { return self._s[2767]! } + public var Group_ErrorAddTooMuchBots: String { return self._s[2768]! } + public var Privacy_GroupsAndChannels_CustomShareHelp: String { return self._s[2769]! } + public var Permissions_CellularDataAllowInSettings_v0: String { return self._s[2770]! } public func Wallet_SecureStorageChanged_BiometryText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2763]!, self._r[2763]!, [_0]) + return formatWithArgumentRanges(self._s[2771]!, self._r[2771]!, [_0]) } - public var DialogList_Typing: String { return self._s[2764]! } - public var CallFeedback_IncludeLogs: String { return self._s[2766]! } - public var Checkout_Phone: String { return self._s[2768]! } - public var Login_InfoFirstNamePlaceholder: String { return self._s[2771]! } - public var Privacy_Calls_Integration: String { return self._s[2772]! } - public var Notifications_PermissionsAllow: String { return self._s[2773]! } - public var TwoStepAuth_AddHintDescription: String { return self._s[2777]! } - public var Settings_ChatSettings: String { return self._s[2778]! } - public var Conversation_SendingOptionsTooltip: String { return self._s[2779]! } + public var DialogList_Typing: String { return self._s[2772]! } + public var CallFeedback_IncludeLogs: String { return self._s[2774]! } + public var Checkout_Phone: String { return self._s[2776]! } + public var Login_InfoFirstNamePlaceholder: String { return self._s[2779]! } + public var Privacy_Calls_Integration: String { return self._s[2780]! } + public var Notifications_PermissionsAllow: String { return self._s[2781]! } + public var TwoStepAuth_AddHintDescription: String { return self._s[2786]! } + public var Settings_ChatSettings: String { return self._s[2787]! } + public var Conversation_SendingOptionsTooltip: String { return self._s[2788]! } public func UserInfo_StartSecretChatConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2781]!, self._r[2781]!, [_0]) + return formatWithArgumentRanges(self._s[2790]!, self._r[2790]!, [_0]) } public func Channel_AdminLog_MessageInvitedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2782]!, self._r[2782]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2791]!, self._r[2791]!, [_1, _2]) } - public var GroupRemoved_DeleteUser: String { return self._s[2784]! } + public var GroupRemoved_DeleteUser: String { return self._s[2793]! } public func Channel_AdminLog_PollStopped(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2785]!, self._r[2785]!, [_0]) + return formatWithArgumentRanges(self._s[2794]!, self._r[2794]!, [_0]) } public func PUSH_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2786]!, self._r[2786]!, [_1]) + return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_1]) } - public var Login_ContinueWithLocalization: String { return self._s[2787]! } - public var Watch_Message_ForwardedFrom: String { return self._s[2788]! } - public var TwoStepAuth_EnterEmailCode: String { return self._s[2790]! } - public var Conversation_Unblock: String { return self._s[2791]! } - public var PrivacySettings_DataSettings: String { return self._s[2792]! } - public var WallpaperPreview_PatternPaternApply: String { return self._s[2793]! } - public var Group_PublicLink_Info: String { return self._s[2794]! } + public var Login_ContinueWithLocalization: String { return self._s[2796]! } + public var Watch_Message_ForwardedFrom: String { return self._s[2797]! } + public var TwoStepAuth_EnterEmailCode: String { return self._s[2799]! } + public var Conversation_Unblock: String { return self._s[2800]! } + public var PrivacySettings_DataSettings: String { return self._s[2801]! } + public var WallpaperPreview_PatternPaternApply: String { return self._s[2802]! } + public var Group_PublicLink_Info: String { return self._s[2803]! } public func Wallet_Time_PreciseDate_m1(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2795]!, self._r[2795]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[2804]!, self._r[2804]!, [_1, _2, _3]) } - public var Notifications_InAppNotificationsVibrate: String { return self._s[2796]! } + public var Notifications_InAppNotificationsVibrate: String { return self._s[2805]! } public func Privacy_GroupsAndChannels_InviteToChannelError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2797]!, self._r[2797]!, [_0, _1]) + return formatWithArgumentRanges(self._s[2806]!, self._r[2806]!, [_0, _1]) } - public var OldChannels_ChannelsHeader: String { return self._s[2799]! } - public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2800]! } - public var PrivacySettings_Passcode: String { return self._s[2802]! } - public var Call_Mute: String { return self._s[2803]! } - public var Wallet_Weekday_Yesterday: String { return self._s[2804]! } - public var Passport_Language_dz: String { return self._s[2805]! } - public var Wallet_Receive_AmountHeader: String { return self._s[2806]! } - public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2807]! } - public var Passport_Language_tk: String { return self._s[2808]! } + public var OldChannels_ChannelsHeader: String { return self._s[2808]! } + public var Wallet_RestoreFailed_CreateWallet: String { return self._s[2809]! } + public var PrivacySettings_Passcode: String { return self._s[2811]! } + public var Call_Mute: String { return self._s[2812]! } + public var Wallet_Weekday_Yesterday: String { return self._s[2813]! } + public var Passport_Language_dz: String { return self._s[2814]! } + public var Wallet_Receive_AmountHeader: String { return self._s[2815]! } + public var Wallet_TransactionInfo_OtherFeeInfoUrl: String { return self._s[2816]! } + public var Passport_Language_tk: String { return self._s[2817]! } public func Login_EmailCodeSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2809]!, self._r[2809]!, [_0]) + return formatWithArgumentRanges(self._s[2818]!, self._r[2818]!, [_0]) } - public var Settings_Search: String { return self._s[2810]! } - public var Wallet_Month_ShortFebruary: String { return self._s[2811]! } - public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2812]! } - public var Wallet_Configuration_SourceJSON: String { return self._s[2813]! } - public var Conversation_ContextMenuReply: String { return self._s[2814]! } - public var WallpaperSearch_ColorBrown: String { return self._s[2815]! } - public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2816]! } - public var Tour_Title1: String { return self._s[2817]! } - public var Wallet_Alert_Cancel: String { return self._s[2818]! } - public var Conversation_ClearGroupHistory: String { return self._s[2820]! } - public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2821]! } - public var WallpaperPreview_Motion: String { return self._s[2822]! } + public var Settings_Search: String { return self._s[2819]! } + public var Wallet_Month_ShortFebruary: String { return self._s[2820]! } + public var InfoPlist_NSPhotoLibraryUsageDescription: String { return self._s[2821]! } + public var Wallet_Configuration_SourceJSON: String { return self._s[2822]! } + public var Conversation_ContextMenuReply: String { return self._s[2823]! } + public var WallpaperSearch_ColorBrown: String { return self._s[2824]! } + public var Chat_AttachmentMultipleForwardDisabled: String { return self._s[2825]! } + public var Tour_Title1: String { return self._s[2826]! } + public var Wallet_Alert_Cancel: String { return self._s[2827]! } + public var Conversation_ClearGroupHistory: String { return self._s[2829]! } + public var Wallet_TransactionInfo_RecipientHeader: String { return self._s[2830]! } + public var WallpaperPreview_Motion: String { return self._s[2831]! } public func Checkout_PasswordEntry_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2823]!, self._r[2823]!, [_0]) - } - public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2824]! } - public var Call_RateCall: String { return self._s[2825]! } - public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2826]! } - public var Passport_PasswordCompleteSetup: String { return self._s[2827]! } - public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2828]! } - public var UserInfo_LastNamePlaceholder: String { return self._s[2830]! } - public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[2832]!, self._r[2832]!, [_0]) } - public var Compose_Create: String { return self._s[2833]! } - public var Contacts_InviteToTelegram: String { return self._s[2834]! } - public var GroupInfo_Notifications: String { return self._s[2835]! } - public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2837]! } - public var Message_PinnedLiveLocationMessage: String { return self._s[2838]! } - public var Month_GenApril: String { return self._s[2839]! } - public var Appearance_AutoNightTheme: String { return self._s[2840]! } - public var ChatSettings_AutomaticAudioDownload: String { return self._s[2842]! } - public var Login_CodeSentSms: String { return self._s[2844]! } + public var Wallet_Configuration_ApplyErrorTextJSONInvalidData: String { return self._s[2833]! } + public var Call_RateCall: String { return self._s[2834]! } + public var Channel_AdminLog_BanSendStickersAndGifs: String { return self._s[2835]! } + public var Passport_PasswordCompleteSetup: String { return self._s[2836]! } + public var Conversation_InputTextSilentBroadcastPlaceholder: String { return self._s[2837]! } + public var UserInfo_LastNamePlaceholder: String { return self._s[2839]! } + public func Login_WillCallYou(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[2841]!, self._r[2841]!, [_0]) + } + public var Compose_Create: String { return self._s[2842]! } + public var Contacts_InviteToTelegram: String { return self._s[2843]! } + public var GroupInfo_Notifications: String { return self._s[2844]! } + public var ChatList_DeleteSavedMessagesConfirmationAction: String { return self._s[2846]! } + public var Message_PinnedLiveLocationMessage: String { return self._s[2847]! } + public var Month_GenApril: String { return self._s[2848]! } + public var Appearance_AutoNightTheme: String { return self._s[2849]! } + public var ChatSettings_AutomaticAudioDownload: String { return self._s[2851]! } + public var Login_CodeSentSms: String { return self._s[2853]! } public func UserInfo_UnblockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2845]!, self._r[2845]!, [_0]) + return formatWithArgumentRanges(self._s[2854]!, self._r[2854]!, [_0]) } - public var EmptyGroupInfo_Line3: String { return self._s[2846]! } - public var LogoutOptions_ContactSupportText: String { return self._s[2847]! } - public var Passport_Language_hr: String { return self._s[2848]! } - public var Common_ActionNotAllowedError: String { return self._s[2849]! } + public var EmptyGroupInfo_Line3: String { return self._s[2855]! } + public var LogoutOptions_ContactSupportText: String { return self._s[2856]! } + public var Passport_Language_hr: String { return self._s[2857]! } + public var Common_ActionNotAllowedError: String { return self._s[2858]! } public func Channel_AdminLog_MessageRestrictedNewSetting(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2850]!, self._r[2850]!, [_0]) + return formatWithArgumentRanges(self._s[2859]!, self._r[2859]!, [_0]) } - public var GroupInfo_InviteLink_CopyLink: String { return self._s[2851]! } - public var Wallet_Info_TransactionFrom: String { return self._s[2852]! } - public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2853]! } - public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2854]! } - public var Privacy_SecretChatsTitle: String { return self._s[2855]! } - public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2857]! } - public var GroupInfo_AddUserLeftError: String { return self._s[2858]! } - public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2859]! } - public var LogoutOptions_ContactSupportTitle: String { return self._s[2860]! } - public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2861]! } - public var Channel_AddBotErrorHaveRights: String { return self._s[2862]! } - public var Preview_DeleteGif: String { return self._s[2863]! } - public var GroupInfo_Permissions_Exceptions: String { return self._s[2864]! } - public var Group_ErrorNotMutualContact: String { return self._s[2865]! } - public var Notification_MessageLifetime5s: String { return self._s[2866]! } - public var Wallet_Send_OwnAddressAlertText: String { return self._s[2867]! } - public var OldChannels_ChannelFormat: String { return self._s[2868]! } + public var GroupInfo_InviteLink_CopyLink: String { return self._s[2860]! } + public var Wallet_Info_TransactionFrom: String { return self._s[2861]! } + public var Wallet_Send_ErrorDecryptionFailed: String { return self._s[2862]! } + public var Conversation_InputTextBroadcastPlaceholder: String { return self._s[2863]! } + public var Privacy_SecretChatsTitle: String { return self._s[2864]! } + public var Notification_SecretChatMessageScreenshotSelf: String { return self._s[2866]! } + public var GroupInfo_AddUserLeftError: String { return self._s[2867]! } + public var AutoDownloadSettings_TypePrivateChats: String { return self._s[2868]! } + public var LogoutOptions_ContactSupportTitle: String { return self._s[2869]! } + public var Appearance_ThemePreview_Chat_7_Text: String { return self._s[2870]! } + public var Channel_AddBotErrorHaveRights: String { return self._s[2871]! } + public var Preview_DeleteGif: String { return self._s[2872]! } + public var GroupInfo_Permissions_Exceptions: String { return self._s[2873]! } + public var Group_ErrorNotMutualContact: String { return self._s[2874]! } + public var Notification_MessageLifetime5s: String { return self._s[2875]! } + public var Wallet_Send_OwnAddressAlertText: String { return self._s[2876]! } + public var OldChannels_ChannelFormat: String { return self._s[2877]! } public func Watch_LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2869]!, self._r[2869]!, [_0]) + return formatWithArgumentRanges(self._s[2878]!, self._r[2878]!, [_0]) } - public var VoiceOver_Chat_Video: String { return self._s[2870]! } - public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2872]! } - public var ReportSpam_DeleteThisChat: String { return self._s[2873]! } - public var Passport_Address_AddBankStatement: String { return self._s[2874]! } - public var Notification_CallIncoming: String { return self._s[2875]! } - public var Wallet_Words_NotDoneTitle: String { return self._s[2876]! } - public var Compose_NewGroupTitle: String { return self._s[2877]! } - public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2879]! } - public var Passport_Address_Postcode: String { return self._s[2881]! } + public var VoiceOver_Chat_Video: String { return self._s[2879]! } + public var Channel_OwnershipTransfer_ErrorPublicChannelsTooMuch: String { return self._s[2881]! } + public var ReportSpam_DeleteThisChat: String { return self._s[2882]! } + public var Passport_Address_AddBankStatement: String { return self._s[2883]! } + public var Notification_CallIncoming: String { return self._s[2884]! } + public var Wallet_Words_NotDoneTitle: String { return self._s[2885]! } + public var Compose_NewGroupTitle: String { return self._s[2886]! } + public var TwoStepAuth_RecoveryCodeHelp: String { return self._s[2888]! } + public var Passport_Address_Postcode: String { return self._s[2890]! } public func LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2882]!, self._r[2882]!, [_0]) + return formatWithArgumentRanges(self._s[2891]!, self._r[2891]!, [_0]) } - public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2883]! } - public var Wallet_Month_ShortOctober: String { return self._s[2884]! } - public var VoiceOver_Chat_YourMusic: String { return self._s[2885]! } - public var WallpaperColors_Title: String { return self._s[2886]! } - public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2887]! } - public var VoiceOver_MessageContextForward: String { return self._s[2888]! } - public var GroupPermission_Duration: String { return self._s[2889]! } + public var Checkout_NewCard_SaveInfoHelp: String { return self._s[2892]! } + public var Wallet_Month_ShortOctober: String { return self._s[2893]! } + public var VoiceOver_Chat_YourMusic: String { return self._s[2894]! } + public var WallpaperColors_Title: String { return self._s[2895]! } + public var SocksProxySetup_ShareQRCodeInfo: String { return self._s[2896]! } + public var VoiceOver_MessageContextForward: String { return self._s[2897]! } + public var GroupPermission_Duration: String { return self._s[2898]! } public func Cache_Clear(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2890]!, self._r[2890]!, [_0]) + return formatWithArgumentRanges(self._s[2899]!, self._r[2899]!, [_0]) } - public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2891]! } - public var Username_Placeholder: String { return self._s[2892]! } - public var CallFeedback_WhatWentWrong: String { return self._s[2893]! } - public var Passport_FieldAddressUploadHelp: String { return self._s[2894]! } - public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2895]! } + public var Bot_GroupStatusDoesNotReadHistory: String { return self._s[2900]! } + public var Username_Placeholder: String { return self._s[2901]! } + public var CallFeedback_WhatWentWrong: String { return self._s[2902]! } + public var Passport_FieldAddressUploadHelp: String { return self._s[2903]! } + public var Permissions_NotificationsAllowInSettings_v0: String { return self._s[2904]! } public func Channel_AdminLog_MessageChangedUnlinkedChannel(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2897]!, self._r[2897]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2906]!, self._r[2906]!, [_1, _2]) } - public var Passport_PasswordDescription: String { return self._s[2898]! } - public var Channel_MessagePhotoUpdated: String { return self._s[2899]! } - public var MediaPicker_TapToUngroupDescription: String { return self._s[2900]! } - public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2901]! } - public var AttachmentMenu_PhotoOrVideo: String { return self._s[2902]! } - public var Conversation_ContextMenuMore: String { return self._s[2903]! } - public var Privacy_PaymentsClearInfo: String { return self._s[2904]! } - public var CallSettings_TabIcon: String { return self._s[2905]! } - public var KeyCommand_Find: String { return self._s[2906]! } - public var ClearCache_FreeSpaceDescription: String { return self._s[2907]! } - public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2908]! } - public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2909]! } - public var Message_PinnedGame: String { return self._s[2910]! } - public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2911]! } - public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2913]! } - public var Login_CallRequestState2: String { return self._s[2915]! } - public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2917]! } + public var Passport_PasswordDescription: String { return self._s[2907]! } + public var Channel_MessagePhotoUpdated: String { return self._s[2908]! } + public var MediaPicker_TapToUngroupDescription: String { return self._s[2909]! } + public var SettingsSearch_Synonyms_Notifications_BadgeCountUnreadMessages: String { return self._s[2910]! } + public var AttachmentMenu_PhotoOrVideo: String { return self._s[2911]! } + public var Conversation_ContextMenuMore: String { return self._s[2912]! } + public var Privacy_PaymentsClearInfo: String { return self._s[2913]! } + public var CallSettings_TabIcon: String { return self._s[2914]! } + public var KeyCommand_Find: String { return self._s[2915]! } + public var ClearCache_FreeSpaceDescription: String { return self._s[2916]! } + public var Appearance_ThemePreview_ChatList_7_Text: String { return self._s[2917]! } + public var EditTheme_Edit_Preview_IncomingText: String { return self._s[2918]! } + public var Message_PinnedGame: String { return self._s[2919]! } + public var VoiceOver_Chat_ForwardedFromYou: String { return self._s[2920]! } + public var Notifications_Badge_CountUnreadMessages_InfoOff: String { return self._s[2922]! } + public var Login_CallRequestState2: String { return self._s[2924]! } + public var CheckoutInfo_ReceiverInfoNamePlaceholder: String { return self._s[2926]! } public func VoiceOver_Chat_PhotoFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2918]!, self._r[2918]!, [_0]) + return formatWithArgumentRanges(self._s[2927]!, self._r[2927]!, [_0]) } public func Checkout_PayPrice(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2920]!, self._r[2920]!, [_0]) + return formatWithArgumentRanges(self._s[2929]!, self._r[2929]!, [_0]) } - public var AuthSessions_AddDevice: String { return self._s[2921]! } - public var WallpaperPreview_Blurred: String { return self._s[2922]! } - public var Conversation_InstantPagePreview: String { return self._s[2923]! } + public var AuthSessions_AddDevice: String { return self._s[2930]! } + public var WallpaperPreview_Blurred: String { return self._s[2931]! } + public var Conversation_InstantPagePreview: String { return self._s[2932]! } public func DialogList_SingleUploadingVideoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2924]!, self._r[2924]!, [_0]) + return formatWithArgumentRanges(self._s[2933]!, self._r[2933]!, [_0]) } - public var SecretTimer_VideoDescription: String { return self._s[2927]! } - public var WallpaperSearch_ColorRed: String { return self._s[2928]! } - public var GroupPermission_NoPinMessages: String { return self._s[2929]! } - public var Passport_Language_es: String { return self._s[2930]! } - public var Permissions_ContactsAllow_v0: String { return self._s[2932]! } - public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2933]! } + public var SecretTimer_VideoDescription: String { return self._s[2936]! } + public var WallpaperSearch_ColorRed: String { return self._s[2937]! } + public var GroupPermission_NoPinMessages: String { return self._s[2938]! } + public var Passport_Language_es: String { return self._s[2939]! } + public var Permissions_ContactsAllow_v0: String { return self._s[2941]! } + public var Conversation_EditingMessageMediaEditCurrentVideo: String { return self._s[2942]! } public func PUSH_CHAT_MESSAGE_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2934]!, self._r[2934]!, [_1, _2]) + return formatWithArgumentRanges(self._s[2943]!, self._r[2943]!, [_1, _2]) } - public var Privacy_Forwards_CustomHelp: String { return self._s[2935]! } - public var WebPreview_GettingLinkInfo: String { return self._s[2936]! } - public var Watch_UserInfo_Unmute: String { return self._s[2937]! } - public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2938]! } - public var AccessDenied_CameraRestricted: String { return self._s[2940]! } + public var Privacy_Forwards_CustomHelp: String { return self._s[2944]! } + public var WebPreview_GettingLinkInfo: String { return self._s[2945]! } + public var Watch_UserInfo_Unmute: String { return self._s[2946]! } + public var GroupInfo_ChannelListNamePlaceholder: String { return self._s[2947]! } + public var AccessDenied_CameraRestricted: String { return self._s[2949]! } public func Conversation_Kilobytes(_ _0: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2941]!, self._r[2941]!, ["\(_0)"]) + return formatWithArgumentRanges(self._s[2950]!, self._r[2950]!, ["\(_0)"]) } - public var ChatList_ReadAll: String { return self._s[2943]! } - public var Settings_CopyUsername: String { return self._s[2944]! } - public var Contacts_SearchLabel: String { return self._s[2945]! } - public var Map_OpenInYandexNavigator: String { return self._s[2947]! } - public var PasscodeSettings_EncryptData: String { return self._s[2948]! } - public var Settings_Wallet: String { return self._s[2949]! } - public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2950]! } - public var WallpaperSearch_ColorPrefix: String { return self._s[2951]! } - public var Notifications_GroupNotificationsPreview: String { return self._s[2952]! } - public var DialogList_AdNoticeAlert: String { return self._s[2953]! } - public var Wallet_Month_GenMay: String { return self._s[2955]! } - public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2956]! } - public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2957]! } - public var Localization_LanguageCustom: String { return self._s[2958]! } - public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2959]! } - public var CallFeedback_Title: String { return self._s[2960]! } - public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2963]! } - public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2964]! } - public var Wallet_Intro_CreateErrorTitle: String { return self._s[2965]! } - public var Conversation_InfoGroup: String { return self._s[2966]! } - public var Compose_NewMessage: String { return self._s[2967]! } - public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2968]! } - public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2969]! } - public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2970]! } - public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2971]! } + public var ChatList_ReadAll: String { return self._s[2952]! } + public var Settings_CopyUsername: String { return self._s[2953]! } + public var Contacts_SearchLabel: String { return self._s[2954]! } + public var Map_OpenInYandexNavigator: String { return self._s[2956]! } + public var PasscodeSettings_EncryptData: String { return self._s[2957]! } + public var Settings_Wallet: String { return self._s[2958]! } + public var Group_ErrorSupergroupConversionNotPossible: String { return self._s[2959]! } + public var WallpaperSearch_ColorPrefix: String { return self._s[2960]! } + public var Notifications_GroupNotificationsPreview: String { return self._s[2961]! } + public var DialogList_AdNoticeAlert: String { return self._s[2962]! } + public var Wallet_Month_GenMay: String { return self._s[2964]! } + public var CheckoutInfo_ShippingInfoAddress1: String { return self._s[2965]! } + public var CheckoutInfo_ShippingInfoAddress2: String { return self._s[2966]! } + public var Localization_LanguageCustom: String { return self._s[2967]! } + public var Passport_Identity_TypeDriversLicenseUploadScan: String { return self._s[2968]! } + public var CallFeedback_Title: String { return self._s[2969]! } + public var VoiceOver_Chat_RecordPreviewVoiceMessage: String { return self._s[2972]! } + public var Passport_Address_OneOfTypePassportRegistration: String { return self._s[2973]! } + public var Wallet_Intro_CreateErrorTitle: String { return self._s[2974]! } + public var Conversation_InfoGroup: String { return self._s[2975]! } + public var Compose_NewMessage: String { return self._s[2976]! } + public var FastTwoStepSetup_HintPlaceholder: String { return self._s[2977]! } + public var ChatSettings_AutoDownloadVideoMessages: String { return self._s[2978]! } + public var Wallet_SecureStorageReset_BiometryFaceId: String { return self._s[2979]! } + public var Channel_DiscussionGroup_UnlinkChannel: String { return self._s[2980]! } public func Passport_Scans_ScanIndex(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2972]!, self._r[2972]!, [_0]) + return formatWithArgumentRanges(self._s[2981]!, self._r[2981]!, [_0]) } - public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2973]! } - public var Login_CancelSignUpConfirmation: String { return self._s[2974]! } - public var ChangePhoneNumberCode_Help: String { return self._s[2975]! } - public var PrivacySettings_DeleteAccountHelp: String { return self._s[2976]! } - public var Channel_BlackList_Title: String { return self._s[2977]! } - public var UserInfo_PhoneCall: String { return self._s[2978]! } - public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2980]! } - public var Wallet_Month_ShortJanuary: String { return self._s[2981]! } - public var State_connecting: String { return self._s[2982]! } - public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2983]! } - public var Wallet_Month_GenMarch: String { return self._s[2984]! } - public var EditTheme_Expand_BottomInfo: String { return self._s[2985]! } - public var AuthSessions_AddedDeviceTerminate: String { return self._s[2986]! } + public var Channel_AdminLog_CanDeleteMessages: String { return self._s[2982]! } + public var Login_CancelSignUpConfirmation: String { return self._s[2983]! } + public var ChangePhoneNumberCode_Help: String { return self._s[2984]! } + public var PrivacySettings_DeleteAccountHelp: String { return self._s[2985]! } + public var Channel_BlackList_Title: String { return self._s[2986]! } + public var UserInfo_PhoneCall: String { return self._s[2987]! } + public var Passport_Address_OneOfTypeBankStatement: String { return self._s[2989]! } + public var Wallet_Month_ShortJanuary: String { return self._s[2990]! } + public var State_connecting: String { return self._s[2991]! } + public var Appearance_ThemePreview_ChatList_6_Text: String { return self._s[2992]! } + public var Wallet_Month_GenMarch: String { return self._s[2993]! } + public var EditTheme_Expand_BottomInfo: String { return self._s[2994]! } + public var AuthSessions_AddedDeviceTerminate: String { return self._s[2995]! } public func LastSeen_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2987]!, self._r[2987]!, [_0]) + return formatWithArgumentRanges(self._s[2996]!, self._r[2996]!, [_0]) } public func DialogList_SingleRecordingAudioSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[2988]!, self._r[2988]!, [_0]) + return formatWithArgumentRanges(self._s[2997]!, self._r[2997]!, [_0]) } - public var Notifications_GroupNotifications: String { return self._s[2989]! } - public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2990]! } - public var Passport_Identity_EditPassport: String { return self._s[2991]! } - public var EnterPasscode_RepeatNewPasscode: String { return self._s[2993]! } - public var Localization_EnglishLanguageName: String { return self._s[2994]! } - public var Share_AuthDescription: String { return self._s[2995]! } - public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[2996]! } - public var Passport_Identity_Surname: String { return self._s[2997]! } - public var Compose_TokenListPlaceholder: String { return self._s[2998]! } - public var Wallet_AccessDenied_Camera: String { return self._s[2999]! } - public var Passport_Identity_OneOfTypePassport: String { return self._s[3000]! } - public var Settings_AboutEmpty: String { return self._s[3001]! } - public var Conversation_Unmute: String { return self._s[3002]! } - public var CreateGroup_ChannelsTooMuch: String { return self._s[3004]! } - public var Wallet_Sending_Text: String { return self._s[3005]! } + public var Notifications_GroupNotifications: String { return self._s[2998]! } + public var Conversation_SendMessageErrorTooMuchScheduled: String { return self._s[2999]! } + public var Passport_Identity_EditPassport: String { return self._s[3000]! } + public var EnterPasscode_RepeatNewPasscode: String { return self._s[3002]! } + public var Localization_EnglishLanguageName: String { return self._s[3003]! } + public var Share_AuthDescription: String { return self._s[3004]! } + public var SettingsSearch_Synonyms_Notifications_ChannelNotificationsAlert: String { return self._s[3005]! } + public var Passport_Identity_Surname: String { return self._s[3006]! } + public var Compose_TokenListPlaceholder: String { return self._s[3007]! } + public var Wallet_AccessDenied_Camera: String { return self._s[3008]! } + public var Passport_Identity_OneOfTypePassport: String { return self._s[3009]! } + public var Settings_AboutEmpty: String { return self._s[3010]! } + public var Conversation_Unmute: String { return self._s[3011]! } + public var CreateGroup_ChannelsTooMuch: String { return self._s[3013]! } + public var Wallet_Sending_Text: String { return self._s[3014]! } public func PUSH_CONTACT_JOINED(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3006]!, self._r[3006]!, [_1]) + return formatWithArgumentRanges(self._s[3015]!, self._r[3015]!, [_1]) } - public var Login_CodeSentCall: String { return self._s[3007]! } - public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3009]! } - public var ChatSettings_Appearance: String { return self._s[3010]! } - public var ClearCache_StorageUsage: String { return self._s[3011]! } - public var Appearance_PickAccentColor: String { return self._s[3012]! } + public var Login_CodeSentCall: String { return self._s[3016]! } + public var ContactInfo_PhoneLabelHomeFax: String { return self._s[3018]! } + public var ChatSettings_Appearance: String { return self._s[3019]! } + public var ClearCache_StorageUsage: String { return self._s[3020]! } + public var Appearance_PickAccentColor: String { return self._s[3021]! } public func PUSH_CHAT_MESSAGE_NOTEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3013]!, self._r[3013]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3022]!, self._r[3022]!, [_1, _2]) } public func PUSH_MESSAGE_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3014]!, self._r[3014]!, [_1]) + return formatWithArgumentRanges(self._s[3023]!, self._r[3023]!, [_1]) } - public var Notification_CallMissed: String { return self._s[3015]! } - public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3016]! } - public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3017]! } - public var Wallet_Month_GenOctober: String { return self._s[3019]! } - public var ChatAdmins_AdminLabel: String { return self._s[3020]! } - public var KeyCommand_JumpToNextChat: String { return self._s[3021]! } - public var Conversation_StopPollConfirmationTitle: String { return self._s[3023]! } - public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3024]! } - public var Month_GenJune: String { return self._s[3025]! } - public var IntentsSettings_MainAccountInfo: String { return self._s[3026]! } - public var Watch_Location_Current: String { return self._s[3027]! } - public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3028]! } - public var Conversation_TitleMute: String { return self._s[3029]! } - public var Map_PlacesInThisArea: String { return self._s[3030]! } + public var Notification_CallMissed: String { return self._s[3024]! } + public var SettingsSearch_Synonyms_Appearance_ChatBackground_Custom: String { return self._s[3025]! } + public var Channel_AdminLogFilter_EventsInfo: String { return self._s[3026]! } + public var Wallet_Month_GenOctober: String { return self._s[3028]! } + public var ChatAdmins_AdminLabel: String { return self._s[3029]! } + public var KeyCommand_JumpToNextChat: String { return self._s[3030]! } + public var Conversation_StopPollConfirmationTitle: String { return self._s[3032]! } + public var ChangePhoneNumberCode_CodePlaceholder: String { return self._s[3033]! } + public var Month_GenJune: String { return self._s[3034]! } + public var IntentsSettings_MainAccountInfo: String { return self._s[3035]! } + public var Watch_Location_Current: String { return self._s[3036]! } + public var Wallet_Receive_CopyInvoiceUrl: String { return self._s[3037]! } + public var Conversation_TitleMute: String { return self._s[3038]! } + public var Map_PlacesInThisArea: String { return self._s[3039]! } public func PUSH_CHANNEL_MESSAGE_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3031]!, self._r[3031]!, [_1]) + return formatWithArgumentRanges(self._s[3040]!, self._r[3040]!, [_1]) } - public var GroupInfo_DeleteAndExit: String { return self._s[3032]! } + public var GroupInfo_DeleteAndExit: String { return self._s[3041]! } public func Conversation_Moderate_DeleteAllMessages(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3033]!, self._r[3033]!, [_0]) + return formatWithArgumentRanges(self._s[3042]!, self._r[3042]!, [_0]) } - public var Call_ReportPlaceholder: String { return self._s[3034]! } - public var Chat_SlowmodeSendError: String { return self._s[3035]! } - public var MaskStickerSettings_Info: String { return self._s[3036]! } - public var EditTheme_Expand_TopInfo: String { return self._s[3037]! } + public var Call_ReportPlaceholder: String { return self._s[3043]! } + public var Chat_SlowmodeSendError: String { return self._s[3044]! } + public var MaskStickerSettings_Info: String { return self._s[3045]! } + public var EditTheme_Expand_TopInfo: String { return self._s[3046]! } public func GroupInfo_AddParticipantConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3038]!, self._r[3038]!, [_0]) + return formatWithArgumentRanges(self._s[3047]!, self._r[3047]!, [_0]) } - public var Checkout_NewCard_PostcodeTitle: String { return self._s[3039]! } - public var Passport_Address_RegionPlaceholder: String { return self._s[3041]! } - public var Contacts_ShareTelegram: String { return self._s[3042]! } - public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3043]! } - public var Map_AddressOnMap: String { return self._s[3044]! } - public var Channel_ErrorAccessDenied: String { return self._s[3045]! } - public var UserInfo_ScamBotWarning: String { return self._s[3047]! } - public var Stickers_GroupChooseStickerPack: String { return self._s[3048]! } - public var Call_ConnectionErrorTitle: String { return self._s[3049]! } - public var UserInfo_NotificationsEnable: String { return self._s[3050]! } - public var ArchivedChats_IntroText1: String { return self._s[3051]! } - public var Tour_Text4: String { return self._s[3054]! } - public var WallpaperSearch_Recent: String { return self._s[3055]! } - public var GroupInfo_ScamGroupWarning: String { return self._s[3056]! } - public var Profile_MessageLifetime2s: String { return self._s[3058]! } - public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3059]! } - public var Notification_MessageLifetime2s: String { return self._s[3060]! } + public var Checkout_NewCard_PostcodeTitle: String { return self._s[3048]! } + public var Passport_Address_RegionPlaceholder: String { return self._s[3050]! } + public var Contacts_ShareTelegram: String { return self._s[3051]! } + public var EnterPasscode_EnterNewPasscodeNew: String { return self._s[3052]! } + public var Map_AddressOnMap: String { return self._s[3053]! } + public var Channel_ErrorAccessDenied: String { return self._s[3054]! } + public var UserInfo_ScamBotWarning: String { return self._s[3056]! } + public var Stickers_GroupChooseStickerPack: String { return self._s[3057]! } + public var Call_ConnectionErrorTitle: String { return self._s[3058]! } + public var UserInfo_NotificationsEnable: String { return self._s[3059]! } + public var ArchivedChats_IntroText1: String { return self._s[3060]! } + public var Tour_Text4: String { return self._s[3063]! } + public var WallpaperSearch_Recent: String { return self._s[3064]! } + public var GroupInfo_ScamGroupWarning: String { return self._s[3065]! } + public var PeopleNearby_MakeVisibleTitle: String { return self._s[3066]! } + public var Profile_MessageLifetime2s: String { return self._s[3068]! } + public var Appearance_ThemePreview_ChatList_5_Text: String { return self._s[3069]! } + public var Notification_MessageLifetime2s: String { return self._s[3070]! } public func Time_PreciseDate_m10(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3061]!, self._r[3061]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3071]!, self._r[3071]!, [_1, _2, _3]) } - public var Cache_ClearCache: String { return self._s[3062]! } - public var AutoNightTheme_UpdateLocation: String { return self._s[3063]! } - public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3064]! } + public var Cache_ClearCache: String { return self._s[3072]! } + public var AutoNightTheme_UpdateLocation: String { return self._s[3073]! } + public var Permissions_NotificationsUnreachableText_v0: String { return self._s[3074]! } public func Channel_AdminLog_MessageChangedGroupUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3068]!, self._r[3068]!, [_0]) + return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_0]) } public func Conversation_ShareMyPhoneNumber_StatusSuccess(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3070]!, self._r[3070]!, [_0]) + return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_0]) } - public var LocalGroup_Text: String { return self._s[3071]! } - public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3072]! } - public var SocksProxySetup_TypeSocks: String { return self._s[3073]! } - public var ChatList_UnarchiveAction: String { return self._s[3074]! } - public var AutoNightTheme_Title: String { return self._s[3075]! } - public var InstantPage_FeedbackButton: String { return self._s[3076]! } - public var Passport_FieldAddress: String { return self._s[3077]! } + public var LocalGroup_Text: String { return self._s[3081]! } + public var Channel_AdminLog_EmptyFilterTitle: String { return self._s[3082]! } + public var SocksProxySetup_TypeSocks: String { return self._s[3083]! } + public var ChatList_UnarchiveAction: String { return self._s[3084]! } + public var AutoNightTheme_Title: String { return self._s[3085]! } + public var InstantPage_FeedbackButton: String { return self._s[3086]! } + public var Passport_FieldAddress: String { return self._s[3087]! } public func Channel_AdminLog_SetSlowmode(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3078]!, self._r[3078]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3088]!, self._r[3088]!, [_1, _2]) } - public var Month_ShortMarch: String { return self._s[3079]! } + public var Month_ShortMarch: String { return self._s[3089]! } public func PUSH_MESSAGE_INVOICE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3080]!, self._r[3080]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3090]!, self._r[3090]!, [_1, _2]) } - public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3081]! } - public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3082]! } - public var Passport_FloodError: String { return self._s[3083]! } - public var SecretGif_Title: String { return self._s[3084]! } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3085]! } - public var ChatList_Context_UnhideArchive: String { return self._s[3086]! } - public var Passport_Language_th: String { return self._s[3088]! } - public var Passport_Address_Address: String { return self._s[3089]! } - public var Login_InvalidLastNameError: String { return self._s[3090]! } - public var Notifications_InAppNotificationsPreview: String { return self._s[3091]! } - public var Notifications_PermissionsUnreachableTitle: String { return self._s[3092]! } - public var ChatList_Context_Archive: String { return self._s[3093]! } - public var SettingsSearch_FAQ: String { return self._s[3094]! } - public var ShareMenu_Send: String { return self._s[3095]! } - public var WallpaperSearch_ColorYellow: String { return self._s[3097]! } - public var Month_GenNovember: String { return self._s[3099]! } - public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3101]! } + public var SocksProxySetup_UsernamePlaceholder: String { return self._s[3091]! } + public var Conversation_ShareInlineBotLocationConfirmation: String { return self._s[3092]! } + public var Passport_FloodError: String { return self._s[3093]! } + public var SecretGif_Title: String { return self._s[3094]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOn: String { return self._s[3095]! } + public var ChatList_Context_UnhideArchive: String { return self._s[3096]! } + public var Passport_Language_th: String { return self._s[3098]! } + public var Passport_Address_Address: String { return self._s[3099]! } + public var Login_InvalidLastNameError: String { return self._s[3100]! } + public var Notifications_InAppNotificationsPreview: String { return self._s[3101]! } + public var Notifications_PermissionsUnreachableTitle: String { return self._s[3102]! } + public var ChatList_Context_Archive: String { return self._s[3103]! } + public var SettingsSearch_FAQ: String { return self._s[3104]! } + public var ShareMenu_Send: String { return self._s[3105]! } + public var WallpaperSearch_ColorYellow: String { return self._s[3107]! } + public var Month_GenNovember: String { return self._s[3109]! } + public var SettingsSearch_Synonyms_Appearance_LargeEmoji: String { return self._s[3111]! } public func Conversation_ShareMyPhoneNumberConfirmation(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3102]!, self._r[3102]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3112]!, self._r[3112]!, [_1, _2]) } - public var Conversation_SwipeToReplyHintText: String { return self._s[3103]! } - public var Checkout_Email: String { return self._s[3104]! } - public var NotificationsSound_Tritone: String { return self._s[3105]! } - public var StickerPacksSettings_ManagingHelp: String { return self._s[3107]! } - public var Wallet_ContextMenuCopy: String { return self._s[3109]! } + public var Conversation_SwipeToReplyHintText: String { return self._s[3113]! } + public var Checkout_Email: String { return self._s[3114]! } + public var NotificationsSound_Tritone: String { return self._s[3115]! } + public var StickerPacksSettings_ManagingHelp: String { return self._s[3117]! } + public var Wallet_ContextMenuCopy: String { return self._s[3119]! } public func Wallet_Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3111]!, self._r[3111]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3121]!, self._r[3121]!, [_1, _2, _3]) } - public var Appearance_TextSize_Automatic: String { return self._s[3112]! } + public var Appearance_TextSize_Automatic: String { return self._s[3122]! } public func PUSH_PINNED_ROUND(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3113]!, self._r[3113]!, [_1]) + return formatWithArgumentRanges(self._s[3123]!, self._r[3123]!, [_1]) } public func StickerPackActionInfo_AddedText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3114]!, self._r[3114]!, [_0]) + return formatWithArgumentRanges(self._s[3124]!, self._r[3124]!, [_0]) } - public var ChangePhoneNumberNumber_Help: String { return self._s[3115]! } + public var ChangePhoneNumberNumber_Help: String { return self._s[3125]! } public func Checkout_LiabilityAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3116]!, self._r[3116]!, [_1, _1, _1, _2]) + return formatWithArgumentRanges(self._s[3126]!, self._r[3126]!, [_1, _1, _1, _2]) } - public var ChatList_UndoArchiveTitle: String { return self._s[3117]! } - public var Notification_Exceptions_Add: String { return self._s[3118]! } - public var DialogList_You: String { return self._s[3119]! } - public var MediaPicker_Send: String { return self._s[3122]! } - public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3123]! } - public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3124]! } - public var Call_AudioRouteSpeaker: String { return self._s[3125]! } - public var Watch_UserInfo_Title: String { return self._s[3126]! } - public var VoiceOver_Chat_PollFinalResults: String { return self._s[3127]! } - public var Appearance_AccentColor: String { return self._s[3129]! } + public var ChatList_UndoArchiveTitle: String { return self._s[3127]! } + public var Notification_Exceptions_Add: String { return self._s[3128]! } + public var DialogList_You: String { return self._s[3129]! } + public var MediaPicker_Send: String { return self._s[3132]! } + public var SettingsSearch_Synonyms_Stickers_Title: String { return self._s[3133]! } + public var Appearance_ThemePreview_ChatList_4_Text: String { return self._s[3134]! } + public var Call_AudioRouteSpeaker: String { return self._s[3135]! } + public var Watch_UserInfo_Title: String { return self._s[3136]! } + public var VoiceOver_Chat_PollFinalResults: String { return self._s[3137]! } + public var Appearance_AccentColor: String { return self._s[3139]! } public func Login_EmailPhoneSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3130]!, self._r[3130]!, [_0]) + return formatWithArgumentRanges(self._s[3140]!, self._r[3140]!, [_0]) } - public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3131]! } + public var Permissions_ContactsAllowInSettings_v0: String { return self._s[3141]! } public func PUSH_CHANNEL_MESSAGE_GAME(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3132]!, self._r[3132]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3142]!, self._r[3142]!, [_1, _2]) } - public var Conversation_ClousStorageInfo_Description2: String { return self._s[3133]! } - public var WebSearch_RecentClearConfirmation: String { return self._s[3134]! } - public var Notification_CallOutgoing: String { return self._s[3135]! } - public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3136]! } - public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3137]! } - public var Call_RecordingDisabledMessage: String { return self._s[3138]! } - public var Message_Game: String { return self._s[3139]! } - public var Conversation_PressVolumeButtonForSound: String { return self._s[3140]! } - public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3141]! } - public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3142]! } - public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3143]! } - public var Date_DialogDateFormat: String { return self._s[3145]! } - public var WallpaperColors_SetCustomColor: String { return self._s[3146]! } - public var Notifications_InAppNotifications: String { return self._s[3147]! } + public var Conversation_ClousStorageInfo_Description2: String { return self._s[3143]! } + public var WebSearch_RecentClearConfirmation: String { return self._s[3144]! } + public var Notification_CallOutgoing: String { return self._s[3145]! } + public var PrivacySettings_PasscodeAndFaceId: String { return self._s[3146]! } + public var Channel_DiscussionGroup_MakeHistoryPublic: String { return self._s[3147]! } + public var Call_RecordingDisabledMessage: String { return self._s[3148]! } + public var Message_Game: String { return self._s[3149]! } + public var Conversation_PressVolumeButtonForSound: String { return self._s[3150]! } + public var PrivacyLastSeenSettings_CustomHelp: String { return self._s[3151]! } + public var Channel_DiscussionGroup_PrivateGroup: String { return self._s[3152]! } + public var Channel_EditAdmin_PermissionAddAdmins: String { return self._s[3153]! } + public var Date_DialogDateFormat: String { return self._s[3155]! } + public var WallpaperColors_SetCustomColor: String { return self._s[3156]! } + public var Notifications_InAppNotifications: String { return self._s[3157]! } public func Channel_Management_RemovedBy(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3148]!, self._r[3148]!, [_0]) + return formatWithArgumentRanges(self._s[3158]!, self._r[3158]!, [_0]) } public func Settings_ApplyProxyAlert(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3149]!, self._r[3149]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3159]!, self._r[3159]!, [_1, _2]) } - public var NewContact_Title: String { return self._s[3150]! } + public var NewContact_Title: String { return self._s[3160]! } public func AutoDownloadSettings_UpToForAll(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3151]!, self._r[3151]!, [_0]) + return formatWithArgumentRanges(self._s[3161]!, self._r[3161]!, [_0]) } - public var Conversation_ViewContactDetails: String { return self._s[3152]! } + public var Conversation_ViewContactDetails: String { return self._s[3162]! } public func PUSH_CHANNEL_MESSAGE_CONTACT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3154]!, self._r[3154]!, [_1]) + return formatWithArgumentRanges(self._s[3164]!, self._r[3164]!, [_1]) } - public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3155]! } - public var Passport_Identity_ExpiryDateNone: String { return self._s[3156]! } - public var PrivacySettings_Title: String { return self._s[3157]! } - public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3160]! } - public var GroupRemoved_UsersSectionTitle: String { return self._s[3161]! } - public var VoiceOver_Chat_ContactEmail: String { return self._s[3162]! } - public var Contacts_PhoneNumber: String { return self._s[3163]! } - public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3165]! } - public var Map_ShowPlaces: String { return self._s[3166]! } - public var ChatAdmins_Title: String { return self._s[3167]! } - public var InstantPage_Reference: String { return self._s[3169]! } - public var Wallet_Info_Updating: String { return self._s[3170]! } - public var ReportGroupLocation_Text: String { return self._s[3171]! } + public var Checkout_NewCard_CardholderNameTitle: String { return self._s[3165]! } + public var Passport_Identity_ExpiryDateNone: String { return self._s[3166]! } + public var PrivacySettings_Title: String { return self._s[3167]! } + public var Conversation_SilentBroadcastTooltipOff: String { return self._s[3170]! } + public var GroupRemoved_UsersSectionTitle: String { return self._s[3171]! } + public var VoiceOver_Chat_ContactEmail: String { return self._s[3172]! } + public var Contacts_PhoneNumber: String { return self._s[3173]! } + public var TwoFactorSetup_Password_PlaceholderConfirmPassword: String { return self._s[3175]! } + public var Map_ShowPlaces: String { return self._s[3176]! } + public var ChatAdmins_Title: String { return self._s[3177]! } + public var InstantPage_Reference: String { return self._s[3179]! } + public var Wallet_Info_Updating: String { return self._s[3180]! } + public var ReportGroupLocation_Text: String { return self._s[3181]! } public func PUSH_CHAT_MESSAGE_FWD(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3172]!, self._r[3172]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3182]!, self._r[3182]!, [_1, _2]) } - public var Camera_FlashOff: String { return self._s[3173]! } - public var Watch_UserInfo_Block: String { return self._s[3174]! } - public var ChatSettings_Stickers: String { return self._s[3175]! } - public var ChatSettings_DownloadInBackground: String { return self._s[3176]! } - public var Appearance_ThemeCarouselTintedNight: String { return self._s[3177]! } + public var Camera_FlashOff: String { return self._s[3183]! } + public var Watch_UserInfo_Block: String { return self._s[3184]! } + public var ChatSettings_Stickers: String { return self._s[3185]! } + public var ChatSettings_DownloadInBackground: String { return self._s[3186]! } + public var Appearance_ThemeCarouselTintedNight: String { return self._s[3187]! } public func UserInfo_BlockConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3178]!, self._r[3178]!, [_0]) + return formatWithArgumentRanges(self._s[3188]!, self._r[3188]!, [_0]) } - public var Settings_ViewPhoto: String { return self._s[3179]! } - public var Login_CheckOtherSessionMessages: String { return self._s[3180]! } - public var AutoDownloadSettings_Cellular: String { return self._s[3181]! } - public var Wallet_Created_ExportErrorTitle: String { return self._s[3182]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3183]! } - public var VoiceOver_MessageContextShare: String { return self._s[3184]! } + public var Settings_ViewPhoto: String { return self._s[3189]! } + public var Login_CheckOtherSessionMessages: String { return self._s[3190]! } + public var AutoDownloadSettings_Cellular: String { return self._s[3191]! } + public var Wallet_Created_ExportErrorTitle: String { return self._s[3192]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsExceptions: String { return self._s[3193]! } + public var VoiceOver_MessageContextShare: String { return self._s[3194]! } public func Target_InviteToGroupConfirmation(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3186]!, self._r[3186]!, [_0]) + return formatWithArgumentRanges(self._s[3196]!, self._r[3196]!, [_0]) } - public var Privacy_DeleteDrafts: String { return self._s[3187]! } - public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3188]! } + public var Privacy_DeleteDrafts: String { return self._s[3197]! } + public var Wallpaper_SetCustomBackgroundInfo: String { return self._s[3198]! } public func LastSeen_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3189]!, self._r[3189]!, [_0]) + return formatWithArgumentRanges(self._s[3199]!, self._r[3199]!, [_0]) } - public var DialogList_SavedMessagesHelp: String { return self._s[3190]! } - public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3191]! } - public var DialogList_SavedMessages: String { return self._s[3192]! } - public var GroupInfo_UpgradeButton: String { return self._s[3193]! } - public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3195]! } - public var DialogList_Pin: String { return self._s[3196]! } + public var DialogList_SavedMessagesHelp: String { return self._s[3200]! } + public var Wallet_SecureStorageNotAvailable_Title: String { return self._s[3201]! } + public var DialogList_SavedMessages: String { return self._s[3202]! } + public var GroupInfo_UpgradeButton: String { return self._s[3203]! } + public var Appearance_ThemePreview_ChatList_3_Text: String { return self._s[3205]! } + public var DialogList_Pin: String { return self._s[3206]! } public func ForwardedAuthors2(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3197]!, self._r[3197]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3207]!, self._r[3207]!, [_0, _1]) } public func Login_PhoneGenericEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3198]!, self._r[3198]!, [_0]) + return formatWithArgumentRanges(self._s[3208]!, self._r[3208]!, [_0]) } - public var Notification_Exceptions_AlwaysOn: String { return self._s[3199]! } - public var UserInfo_NotificationsDisable: String { return self._s[3200]! } - public var Conversation_ContextMenuCancelEditing: String { return self._s[3201]! } - public var Paint_Outlined: String { return self._s[3202]! } - public var Activity_PlayingGame: String { return self._s[3203]! } - public var SearchImages_NoImagesFound: String { return self._s[3204]! } - public var SocksProxySetup_ProxyType: String { return self._s[3205]! } - public var AppleWatch_ReplyPresetsHelp: String { return self._s[3207]! } - public var Conversation_ContextMenuCancelSending: String { return self._s[3208]! } - public var Settings_AppLanguage: String { return self._s[3209]! } - public var TwoStepAuth_ResetAccountHelp: String { return self._s[3210]! } - public var Common_ChoosePhoto: String { return self._s[3211]! } - public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3212]! } - public var CallFeedback_ReasonEcho: String { return self._s[3213]! } + public var Notification_Exceptions_AlwaysOn: String { return self._s[3209]! } + public var UserInfo_NotificationsDisable: String { return self._s[3210]! } + public var Conversation_ContextMenuCancelEditing: String { return self._s[3211]! } + public var Paint_Outlined: String { return self._s[3212]! } + public var Activity_PlayingGame: String { return self._s[3213]! } + public var SearchImages_NoImagesFound: String { return self._s[3214]! } + public var SocksProxySetup_ProxyType: String { return self._s[3215]! } + public var AppleWatch_ReplyPresetsHelp: String { return self._s[3217]! } + public var Conversation_ContextMenuCancelSending: String { return self._s[3218]! } + public var Settings_AppLanguage: String { return self._s[3219]! } + public var TwoStepAuth_ResetAccountHelp: String { return self._s[3220]! } + public var Common_ChoosePhoto: String { return self._s[3221]! } + public var AuthSessions_AddDevice_InvalidQRCode: String { return self._s[3222]! } + public var CallFeedback_ReasonEcho: String { return self._s[3223]! } public func PUSH_PINNED_AUDIO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3214]!, self._r[3214]!, [_1]) + return formatWithArgumentRanges(self._s[3224]!, self._r[3224]!, [_1]) } - public var Privacy_Calls_AlwaysAllow: String { return self._s[3215]! } - public var PollResults_Collapse: String { return self._s[3216]! } - public var Activity_UploadingVideo: String { return self._s[3217]! } - public var Conversation_WalletRequiredNotNow: String { return self._s[3218]! } - public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3219]! } - public var NetworkUsageSettings_Wifi: String { return self._s[3220]! } - public var VoiceOver_Editing_ClearText: String { return self._s[3221]! } - public var PUSH_SENDER_YOU: String { return self._s[3222]! } - public var Channel_BanUser_PermissionReadMessages: String { return self._s[3223]! } - public var Checkout_PayWithTouchId: String { return self._s[3224]! } - public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3225]! } + public var Privacy_Calls_AlwaysAllow: String { return self._s[3225]! } + public var PollResults_Collapse: String { return self._s[3226]! } + public var Activity_UploadingVideo: String { return self._s[3227]! } + public var Conversation_WalletRequiredNotNow: String { return self._s[3228]! } + public var ChannelInfo_DeleteChannelConfirmation: String { return self._s[3229]! } + public var NetworkUsageSettings_Wifi: String { return self._s[3230]! } + public var VoiceOver_Editing_ClearText: String { return self._s[3231]! } + public var PUSH_SENDER_YOU: String { return self._s[3232]! } + public var Channel_BanUser_PermissionReadMessages: String { return self._s[3233]! } + public var Checkout_PayWithTouchId: String { return self._s[3234]! } + public var Wallpaper_ResetWallpapersConfirmation: String { return self._s[3235]! } public func PUSH_LOCKED_MESSAGE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3227]!, self._r[3227]!, [_1]) + return formatWithArgumentRanges(self._s[3237]!, self._r[3237]!, [_1]) } - public var Notifications_ExceptionsNone: String { return self._s[3228]! } + public var Notifications_ExceptionsNone: String { return self._s[3238]! } public func Message_ForwardedMessageShort(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3229]!, self._r[3229]!, [_0]) + return formatWithArgumentRanges(self._s[3239]!, self._r[3239]!, [_0]) } public func PUSH_PINNED_GEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3230]!, self._r[3230]!, [_1]) + return formatWithArgumentRanges(self._s[3240]!, self._r[3240]!, [_1]) } - public var AuthSessions_IncompleteAttempts: String { return self._s[3232]! } - public var Passport_Address_Region: String { return self._s[3235]! } - public var ChatList_DeleteChat: String { return self._s[3236]! } - public var LogoutOptions_ClearCacheTitle: String { return self._s[3237]! } - public var PhotoEditor_TiltShift: String { return self._s[3238]! } - public var Settings_FAQ_URL: String { return self._s[3239]! } - public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3240]! } - public var Passport_Language_sl: String { return self._s[3241]! } - public var Settings_PrivacySettings: String { return self._s[3243]! } - public var SharedMedia_TitleLink: String { return self._s[3244]! } - public var Passport_Identity_TypePassportUploadScan: String { return self._s[3245]! } - public var Settings_SetProfilePhoto: String { return self._s[3246]! } - public var Channel_About_Help: String { return self._s[3247]! } - public var Contacts_PermissionsEnable: String { return self._s[3248]! } - public var Wallet_Sending_Title: String { return self._s[3249]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3250]! } - public var AttachmentMenu_SendAsFiles: String { return self._s[3251]! } - public var CallFeedback_ReasonInterruption: String { return self._s[3253]! } - public var Passport_Address_AddTemporaryRegistration: String { return self._s[3254]! } - public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3255]! } - public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3256]! } - public var OldChannels_Title: String { return self._s[3257]! } - public var PrivacySettings_DeleteAccountTitle: String { return self._s[3258]! } - public var AccessDenied_VideoMessageCamera: String { return self._s[3260]! } - public var Map_OpenInYandexMaps: String { return self._s[3262]! } - public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3263]! } - public var VoiceOver_MessageContextReply: String { return self._s[3264]! } - public var PhotoEditor_SaturationTool: String { return self._s[3266]! } + public var AuthSessions_IncompleteAttempts: String { return self._s[3242]! } + public var Passport_Address_Region: String { return self._s[3245]! } + public var ChatList_DeleteChat: String { return self._s[3246]! } + public var LogoutOptions_ClearCacheTitle: String { return self._s[3247]! } + public var PhotoEditor_TiltShift: String { return self._s[3248]! } + public var Settings_FAQ_URL: String { return self._s[3249]! } + public var TwoFactorSetup_EmailVerification_ChangeAction: String { return self._s[3250]! } + public var Passport_Language_sl: String { return self._s[3251]! } + public var Settings_PrivacySettings: String { return self._s[3253]! } + public var SharedMedia_TitleLink: String { return self._s[3254]! } + public var Passport_Identity_TypePassportUploadScan: String { return self._s[3255]! } + public var Settings_SetProfilePhoto: String { return self._s[3256]! } + public var Channel_About_Help: String { return self._s[3257]! } + public var Contacts_PermissionsEnable: String { return self._s[3258]! } + public var Wallet_Sending_Title: String { return self._s[3259]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsAlert: String { return self._s[3260]! } + public var AttachmentMenu_SendAsFiles: String { return self._s[3261]! } + public var CallFeedback_ReasonInterruption: String { return self._s[3263]! } + public var Passport_Address_AddTemporaryRegistration: String { return self._s[3264]! } + public var AutoDownloadSettings_AutodownloadVideos: String { return self._s[3265]! } + public var ChatSettings_AutoDownloadSettings_Delimeter: String { return self._s[3266]! } + public var OldChannels_Title: String { return self._s[3267]! } + public var PrivacySettings_DeleteAccountTitle: String { return self._s[3268]! } + public var AccessDenied_VideoMessageCamera: String { return self._s[3270]! } + public var Map_OpenInYandexMaps: String { return self._s[3272]! } + public var CreateGroup_ErrorLocatedGroupsTooMuch: String { return self._s[3273]! } + public var VoiceOver_MessageContextReply: String { return self._s[3274]! } + public var PhotoEditor_SaturationTool: String { return self._s[3276]! } public func PUSH_MESSAGE_STICKER(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3267]!, self._r[3267]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3277]!, self._r[3277]!, [_1, _2]) } - public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3268]! } - public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3269]! } - public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3270]! } + public var PrivacyPhoneNumberSettings_CustomHelp: String { return self._s[3278]! } + public var Notification_Exceptions_NewException_NotificationHeader: String { return self._s[3279]! } + public var Group_OwnershipTransfer_ErrorLocatedGroupsTooMuch: String { return self._s[3280]! } public func LOCAL_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3271]!, self._r[3271]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3281]!, self._r[3281]!, [_1, "\(_2)"]) } - public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3272]! } - public var Channel_Username_InvalidTooShort: String { return self._s[3274]! } - public var SettingsSearch_Synonyms_Wallet: String { return self._s[3275]! } + public var Appearance_ThemePreview_ChatList_2_Text: String { return self._s[3282]! } + public var Channel_Username_InvalidTooShort: String { return self._s[3284]! } + public var SettingsSearch_Synonyms_Wallet: String { return self._s[3285]! } public func Group_OwnershipTransfer_DescriptionInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3276]!, self._r[3276]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3286]!, self._r[3286]!, [_1, _2]) } - public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3277]! } + public var Forward_ErrorPublicPollDisabledInChannels: String { return self._s[3287]! } public func PUSH_CHAT_MESSAGE_GAME(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3278]!, self._r[3278]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3288]!, self._r[3288]!, [_1, _2, _3]) } - public var WallpaperPreview_PatternTitle: String { return self._s[3279]! } - public var GroupInfo_PublicLinkAdd: String { return self._s[3280]! } - public var Passport_PassportInformation: String { return self._s[3283]! } - public var Theme_Unsupported: String { return self._s[3284]! } - public var WatchRemote_AlertTitle: String { return self._s[3285]! } - public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3286]! } - public var ConvertToSupergroup_HelpText: String { return self._s[3288]! } + public var WallpaperPreview_PatternTitle: String { return self._s[3289]! } + public var GroupInfo_PublicLinkAdd: String { return self._s[3290]! } + public var Passport_PassportInformation: String { return self._s[3293]! } + public var Theme_Unsupported: String { return self._s[3294]! } + public var WatchRemote_AlertTitle: String { return self._s[3295]! } + public var Privacy_GroupsAndChannels_NeverAllow: String { return self._s[3296]! } + public var ConvertToSupergroup_HelpText: String { return self._s[3298]! } public func Time_MonthOfYear_m7(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3289]!, self._r[3289]!, [_0]) + return formatWithArgumentRanges(self._s[3299]!, self._r[3299]!, [_0]) } public func PUSH_PHONE_CALL_REQUEST(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3290]!, self._r[3290]!, [_1]) + return formatWithArgumentRanges(self._s[3300]!, self._r[3300]!, [_1]) } - public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3291]! } - public var Wallet_Navigation_Done: String { return self._s[3293]! } - public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3294]! } - public var AccessDenied_CameraDisabled: String { return self._s[3295]! } + public var Privacy_GroupsAndChannels_CustomHelp: String { return self._s[3301]! } + public var Wallet_Navigation_Done: String { return self._s[3303]! } + public var TwoStepAuth_RecoveryCodeInvalid: String { return self._s[3304]! } + public var AccessDenied_CameraDisabled: String { return self._s[3305]! } public func Channel_Username_UsernameIsAvailable(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3296]!, self._r[3296]!, [_0]) + return formatWithArgumentRanges(self._s[3306]!, self._r[3306]!, [_0]) } - public var ClearCache_Forever: String { return self._s[3297]! } - public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3298]! } - public var CreatePoll_Quiz: String { return self._s[3299]! } - public var PhotoEditor_ContrastTool: String { return self._s[3302]! } + public var ClearCache_Forever: String { return self._s[3307]! } + public var AuthSessions_AddDeviceIntro_Title: String { return self._s[3308]! } + public var CreatePoll_Quiz: String { return self._s[3309]! } + public var PhotoEditor_ContrastTool: String { return self._s[3312]! } public func PUSH_PINNED_DOC(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3303]!, self._r[3303]!, [_1]) + return formatWithArgumentRanges(self._s[3313]!, self._r[3313]!, [_1]) } - public var DialogList_Draft: String { return self._s[3304]! } - public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3305]! } - public var Privacy_TopPeersDelete: String { return self._s[3307]! } - public var LoginPassword_PasswordPlaceholder: String { return self._s[3308]! } - public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3309]! } - public var WebSearch_RecentSectionClear: String { return self._s[3310]! } - public var EditTheme_ErrorInvalidCharacters: String { return self._s[3311]! } - public var Watch_ChatList_NoConversationsTitle: String { return self._s[3313]! } - public var Common_Done: String { return self._s[3315]! } - public var Shortcut_SwitchAccount: String { return self._s[3316]! } - public var AuthSessions_EmptyText: String { return self._s[3317]! } - public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3318]! } - public var Conversation_ShareBotContactConfirmation: String { return self._s[3319]! } - public var Tour_Title5: String { return self._s[3320]! } - public var Wallet_Settings_Title: String { return self._s[3321]! } + public var DialogList_Draft: String { return self._s[3314]! } + public var Wallet_Configuration_BlockchainIdInfo: String { return self._s[3315]! } + public func PeopleNearby_VisibleUntil(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3316]!, self._r[3316]!, [_0]) + } + public var Privacy_TopPeersDelete: String { return self._s[3318]! } + public var LoginPassword_PasswordPlaceholder: String { return self._s[3319]! } + public var Passport_Identity_TypeIdentityCardUploadScan: String { return self._s[3320]! } + public var WebSearch_RecentSectionClear: String { return self._s[3321]! } + public var EditTheme_ErrorInvalidCharacters: String { return self._s[3322]! } + public var Watch_ChatList_NoConversationsTitle: String { return self._s[3324]! } + public var Common_Done: String { return self._s[3326]! } + public var Shortcut_SwitchAccount: String { return self._s[3327]! } + public var AuthSessions_EmptyText: String { return self._s[3328]! } + public var Wallet_Configuration_BlockchainNameChangedTitle: String { return self._s[3329]! } + public var Conversation_ShareBotContactConfirmation: String { return self._s[3330]! } + public var Tour_Title5: String { return self._s[3331]! } + public var Wallet_Settings_Title: String { return self._s[3332]! } public func Map_DirectionsDriveEta(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3322]!, self._r[3322]!, [_0]) + return formatWithArgumentRanges(self._s[3333]!, self._r[3333]!, [_0]) } - public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3323]! } - public var Conversation_LinkDialogSave: String { return self._s[3324]! } - public var GroupInfo_ActionRestrict: String { return self._s[3325]! } - public var Checkout_Title: String { return self._s[3326]! } - public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3328]! } - public var Channel_AdminLog_CanChangeInfo: String { return self._s[3330]! } - public var Notification_RenamedGroup: String { return self._s[3331]! } - public var PeopleNearby_Groups: String { return self._s[3332]! } - public var Checkout_PayWithFaceId: String { return self._s[3333]! } - public var Channel_BanList_BlockedTitle: String { return self._s[3334]! } - public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3336]! } - public var Checkout_WebConfirmation_Title: String { return self._s[3337]! } - public var Notifications_MessageNotificationsAlert: String { return self._s[3338]! } + public var ApplyLanguage_UnsufficientDataTitle: String { return self._s[3334]! } + public var Conversation_LinkDialogSave: String { return self._s[3335]! } + public var GroupInfo_ActionRestrict: String { return self._s[3336]! } + public var Checkout_Title: String { return self._s[3337]! } + public var Channel_DiscussionGroup_HeaderLabel: String { return self._s[3339]! } + public var Channel_AdminLog_CanChangeInfo: String { return self._s[3341]! } + public var Notification_RenamedGroup: String { return self._s[3342]! } + public var PeopleNearby_Groups: String { return self._s[3343]! } + public var Checkout_PayWithFaceId: String { return self._s[3344]! } + public var Channel_BanList_BlockedTitle: String { return self._s[3345]! } + public var SettingsSearch_Synonyms_Notifications_InAppNotificationsSound: String { return self._s[3347]! } + public var Checkout_WebConfirmation_Title: String { return self._s[3348]! } + public var Notifications_MessageNotificationsAlert: String { return self._s[3349]! } public func Activity_RemindAboutGroup(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3339]!, self._r[3339]!, [_0]) + return formatWithArgumentRanges(self._s[3350]!, self._r[3350]!, [_0]) } - public var Profile_AddToExisting: String { return self._s[3341]! } + public var Profile_AddToExisting: String { return self._s[3352]! } public func Profile_CreateEncryptedChatOutdatedError(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3342]!, self._r[3342]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0, _1]) } - public var Cache_Files: String { return self._s[3344]! } - public var Permissions_PrivacyPolicy: String { return self._s[3345]! } - public var SocksProxySetup_ConnectAndSave: String { return self._s[3346]! } - public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3347]! } - public var AutoDownloadSettings_TypeContacts: String { return self._s[3349]! } - public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3351]! } - public var Calls_NoCallsPlaceholder: String { return self._s[3352]! } + public var Cache_Files: String { return self._s[3355]! } + public var Permissions_PrivacyPolicy: String { return self._s[3356]! } + public var SocksProxySetup_ConnectAndSave: String { return self._s[3357]! } + public var UserInfo_NotificationsDefaultDisabled: String { return self._s[3358]! } + public var AutoDownloadSettings_TypeContacts: String { return self._s[3360]! } + public var Appearance_ThemePreview_ChatList_1_Text: String { return self._s[3362]! } + public var Calls_NoCallsPlaceholder: String { return self._s[3363]! } public func Wallet_Receive_ShareInvoiceUrlInfo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3353]!, self._r[3353]!, [_0]) + return formatWithArgumentRanges(self._s[3364]!, self._r[3364]!, [_0]) } - public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3354]! } - public var VoiceOver_AttachMedia: String { return self._s[3357]! } - public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3358]! } + public var Channel_Username_RevokeExistingUsernamesInfo: String { return self._s[3365]! } + public var VoiceOver_AttachMedia: String { return self._s[3368]! } + public var Notifications_ExceptionsGroupPlaceholder: String { return self._s[3369]! } public func PUSH_CHAT_MESSAGE_INVOICE(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3359]!, self._r[3359]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3370]!, self._r[3370]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3360]! } - public var Conversation_SetReminder_Title: String { return self._s[3361]! } - public var Passport_FieldAddressHelp: String { return self._s[3362]! } - public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3363]! } - public var PUSH_REMINDER_TITLE: String { return self._s[3364]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsSound: String { return self._s[3371]! } + public var Conversation_SetReminder_Title: String { return self._s[3372]! } + public var Passport_FieldAddressHelp: String { return self._s[3373]! } + public var Privacy_GroupsAndChannels_InviteToChannelMultipleError: String { return self._s[3374]! } + public var PUSH_REMINDER_TITLE: String { return self._s[3375]! } public func Login_TermsOfService_ProceedBot(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3365]!, self._r[3365]!, [_0]) + return formatWithArgumentRanges(self._s[3376]!, self._r[3376]!, [_0]) } - public var Channel_AdminLog_EmptyTitle: String { return self._s[3366]! } - public var Privacy_Calls_NeverAllow_Title: String { return self._s[3367]! } - public var Login_UnknownError: String { return self._s[3368]! } - public var Group_UpgradeNoticeText2: String { return self._s[3371]! } - public var Watch_Compose_AddContact: String { return self._s[3372]! } - public var ClearCache_StorageServiceFiles: String { return self._s[3373]! } - public var Web_Error: String { return self._s[3374]! } - public var Gif_Search: String { return self._s[3375]! } - public var Profile_MessageLifetime1h: String { return self._s[3376]! } - public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3377]! } - public var Channel_Username_CheckingUsername: String { return self._s[3378]! } - public var CallFeedback_ReasonSilentRemote: String { return self._s[3379]! } - public var AutoDownloadSettings_TypeChannels: String { return self._s[3380]! } - public var Channel_AboutItem: String { return self._s[3381]! } - public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3383]! } - public var VoiceOver_Chat_VoiceMessage: String { return self._s[3384]! } - public var GroupInfo_SharedMedia: String { return self._s[3385]! } + public var Channel_AdminLog_EmptyTitle: String { return self._s[3377]! } + public var Privacy_Calls_NeverAllow_Title: String { return self._s[3378]! } + public var Login_UnknownError: String { return self._s[3379]! } + public var Group_UpgradeNoticeText2: String { return self._s[3382]! } + public var Watch_Compose_AddContact: String { return self._s[3383]! } + public var ClearCache_StorageServiceFiles: String { return self._s[3384]! } + public var Web_Error: String { return self._s[3385]! } + public var Gif_Search: String { return self._s[3386]! } + public var Profile_MessageLifetime1h: String { return self._s[3387]! } + public var CheckoutInfo_ReceiverInfoEmailPlaceholder: String { return self._s[3388]! } + public var Channel_Username_CheckingUsername: String { return self._s[3389]! } + public var CallFeedback_ReasonSilentRemote: String { return self._s[3390]! } + public var AutoDownloadSettings_TypeChannels: String { return self._s[3391]! } + public var Channel_AboutItem: String { return self._s[3392]! } + public var Privacy_GroupsAndChannels_AlwaysAllow_Placeholder: String { return self._s[3394]! } + public var VoiceOver_Chat_VoiceMessage: String { return self._s[3395]! } + public var GroupInfo_SharedMedia: String { return self._s[3396]! } public func Channel_AdminLog_MessagePromotedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3386]!, self._r[3386]!, [_1]) + return formatWithArgumentRanges(self._s[3397]!, self._r[3397]!, [_1]) } - public var Call_PhoneCallInProgressMessage: String { return self._s[3387]! } + public var Call_PhoneCallInProgressMessage: String { return self._s[3398]! } public func PUSH_CHANNEL_ALBUM(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3388]!, self._r[3388]!, [_1]) + return formatWithArgumentRanges(self._s[3399]!, self._r[3399]!, [_1]) } - public var ChatList_UndoArchiveRevealedText: String { return self._s[3389]! } - public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3390]! } - public var Conversation_SearchByName_Placeholder: String { return self._s[3391]! } - public var CreatePoll_AddOption: String { return self._s[3392]! } - public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3393]! } - public var Group_UpgradeNoticeHeader: String { return self._s[3394]! } - public var Channel_Management_AddModerator: String { return self._s[3395]! } - public var AutoDownloadSettings_MaxFileSize: String { return self._s[3396]! } - public var StickerPacksSettings_ShowStickersButton: String { return self._s[3397]! } - public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3398]! } - public var Theme_Colors_Background: String { return self._s[3399]! } - public var NotificationsSound_Hello: String { return self._s[3401]! } - public var SocksProxySetup_SavedProxies: String { return self._s[3402]! } - public var Channel_Stickers_Placeholder: String { return self._s[3404]! } + public var ChatList_UndoArchiveRevealedText: String { return self._s[3400]! } + public var GroupInfo_InviteLink_RevokeAlert_Text: String { return self._s[3401]! } + public var Conversation_SearchByName_Placeholder: String { return self._s[3402]! } + public var CreatePoll_AddOption: String { return self._s[3403]! } + public var GroupInfo_Permissions_SearchPlaceholder: String { return self._s[3404]! } + public var Group_UpgradeNoticeHeader: String { return self._s[3405]! } + public var Channel_Management_AddModerator: String { return self._s[3406]! } + public var AutoDownloadSettings_MaxFileSize: String { return self._s[3407]! } + public var StickerPacksSettings_ShowStickersButton: String { return self._s[3408]! } + public var Wallet_Info_RefreshErrorNetworkText: String { return self._s[3409]! } + public var Theme_Colors_Background: String { return self._s[3410]! } + public var NotificationsSound_Hello: String { return self._s[3412]! } + public var SocksProxySetup_SavedProxies: String { return self._s[3413]! } + public var Channel_Stickers_Placeholder: String { return self._s[3415]! } public func Login_EmailCodeBody(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3405]!, self._r[3405]!, [_0]) + return formatWithArgumentRanges(self._s[3416]!, self._r[3416]!, [_0]) } - public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3406]! } - public var Channel_Management_AddModeratorHelp: String { return self._s[3407]! } - public var ContactInfo_BirthdayLabel: String { return self._s[3408]! } - public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3409]! } - public var AutoDownloadSettings_Channels: String { return self._s[3410]! } - public var Passport_Language_mn: String { return self._s[3411]! } - public var Notifications_ResetAllNotificationsHelp: String { return self._s[3414]! } - public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3415]! } - public var Passport_Language_ja: String { return self._s[3417]! } - public var Settings_About_Title: String { return self._s[3418]! } - public var Settings_NotificationsAndSounds: String { return self._s[3419]! } - public var ChannelInfo_DeleteGroup: String { return self._s[3420]! } - public var Settings_BlockedUsers: String { return self._s[3421]! } + public var PrivacyPolicy_DeclineDeclineAndDelete: String { return self._s[3417]! } + public var Channel_Management_AddModeratorHelp: String { return self._s[3418]! } + public var ContactInfo_BirthdayLabel: String { return self._s[3419]! } + public var ChangePhoneNumberCode_RequestingACall: String { return self._s[3420]! } + public var AutoDownloadSettings_Channels: String { return self._s[3421]! } + public var Passport_Language_mn: String { return self._s[3422]! } + public var Notifications_ResetAllNotificationsHelp: String { return self._s[3425]! } + public var GroupInfo_Permissions_SlowmodeValue_Off: String { return self._s[3426]! } + public var Passport_Language_ja: String { return self._s[3428]! } + public var Settings_About_Title: String { return self._s[3429]! } + public var Settings_NotificationsAndSounds: String { return self._s[3430]! } + public var ChannelInfo_DeleteGroup: String { return self._s[3431]! } + public var Settings_BlockedUsers: String { return self._s[3432]! } public func Time_MonthOfYear_m4(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3422]!, self._r[3422]!, [_0]) + return formatWithArgumentRanges(self._s[3433]!, self._r[3433]!, [_0]) } - public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3423]! } - public var Wallet_Weekday_Today: String { return self._s[3424]! } - public var AutoDownloadSettings_PreloadVideo: String { return self._s[3425]! } - public var Widget_ApplicationLocked: String { return self._s[3426]! } - public var Passport_Address_AddResidentialAddress: String { return self._s[3427]! } - public var Channel_Username_Title: String { return self._s[3428]! } + public var EditTheme_Create_Preview_OutgoingText: String { return self._s[3434]! } + public var Wallet_Weekday_Today: String { return self._s[3435]! } + public var AutoDownloadSettings_PreloadVideo: String { return self._s[3436]! } + public var Widget_ApplicationLocked: String { return self._s[3437]! } + public var Passport_Address_AddResidentialAddress: String { return self._s[3438]! } + public var Channel_Username_Title: String { return self._s[3439]! } public func Notification_RemovedGroupPhoto(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3429]!, self._r[3429]!, [_0]) + return formatWithArgumentRanges(self._s[3440]!, self._r[3440]!, [_0]) } - public var AttachmentMenu_File: String { return self._s[3431]! } - public var AppleWatch_Title: String { return self._s[3432]! } - public var Activity_RecordingVideoMessage: String { return self._s[3433]! } + public var AttachmentMenu_File: String { return self._s[3442]! } + public var AppleWatch_Title: String { return self._s[3443]! } + public var Activity_RecordingVideoMessage: String { return self._s[3444]! } public func Channel_DiscussionGroup_PublicChannelLink(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3434]!, self._r[3434]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3445]!, self._r[3445]!, [_1, _2]) } - public var Theme_Colors_Messages: String { return self._s[3435]! } - public var Weekday_Saturday: String { return self._s[3436]! } - public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3437]! } - public var Profile_CreateEncryptedChatError: String { return self._s[3438]! } - public var Common_Next: String { return self._s[3440]! } - public var Channel_Stickers_YourStickers: String { return self._s[3442]! } - public var Message_Theme: String { return self._s[3443]! } - public var Call_AudioRouteHeadphones: String { return self._s[3444]! } - public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3446]! } - public var Watch_Contacts_NoResults: String { return self._s[3448]! } - public var PhotoEditor_TintTool: String { return self._s[3451]! } - public var LoginPassword_ResetAccount: String { return self._s[3453]! } - public var Settings_SavedMessages: String { return self._s[3454]! } - public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3455]! } - public var Bot_GenericSupportStatus: String { return self._s[3456]! } - public var StickerPack_Add: String { return self._s[3457]! } - public var Checkout_TotalAmount: String { return self._s[3458]! } - public var Your_cards_number_is_invalid: String { return self._s[3459]! } - public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3460]! } - public var VoiceOver_Chat_VideoMessage: String { return self._s[3461]! } + public var Theme_Colors_Messages: String { return self._s[3446]! } + public var Weekday_Saturday: String { return self._s[3447]! } + public var WallpaperPreview_SwipeColorsTopText: String { return self._s[3448]! } + public var Profile_CreateEncryptedChatError: String { return self._s[3449]! } + public var Common_Next: String { return self._s[3451]! } + public var Channel_Stickers_YourStickers: String { return self._s[3453]! } + public var Message_Theme: String { return self._s[3454]! } + public var Call_AudioRouteHeadphones: String { return self._s[3455]! } + public var TwoStepAuth_EnterPasswordForgot: String { return self._s[3457]! } + public var Watch_Contacts_NoResults: String { return self._s[3459]! } + public var PhotoEditor_TintTool: String { return self._s[3462]! } + public var LoginPassword_ResetAccount: String { return self._s[3464]! } + public var Settings_SavedMessages: String { return self._s[3465]! } + public var SettingsSearch_Synonyms_Appearance_Animations: String { return self._s[3466]! } + public var Bot_GenericSupportStatus: String { return self._s[3467]! } + public var StickerPack_Add: String { return self._s[3468]! } + public var Checkout_TotalAmount: String { return self._s[3469]! } + public var Your_cards_number_is_invalid: String { return self._s[3470]! } + public var SettingsSearch_Synonyms_Appearance_AutoNightTheme: String { return self._s[3471]! } + public var VoiceOver_Chat_VideoMessage: String { return self._s[3472]! } public func ChangePhoneNumberCode_CallTimer(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3462]!, self._r[3462]!, [_0]) + return formatWithArgumentRanges(self._s[3473]!, self._r[3473]!, [_0]) } public func GroupPermission_AddedInfo(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3463]!, self._r[3463]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3474]!, self._r[3474]!, [_1, _2]) } - public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3464]! } + public var ChatSettings_ConnectionType_UseSocks5: String { return self._s[3475]! } public func PUSH_CHAT_PHOTO_EDITED(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3466]!, self._r[3466]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3477]!, self._r[3477]!, [_1, _2]) } public func Conversation_RestrictedTextTimed(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3467]!, self._r[3467]!, [_0]) + return formatWithArgumentRanges(self._s[3478]!, self._r[3478]!, [_0]) } - public var GroupInfo_InviteLink_ShareLink: String { return self._s[3468]! } - public var StickerPack_Share: String { return self._s[3469]! } - public var Passport_DeleteAddress: String { return self._s[3470]! } - public var Settings_Passport: String { return self._s[3471]! } - public var SharedMedia_EmptyFilesText: String { return self._s[3472]! } - public var Conversation_DeleteMessagesForMe: String { return self._s[3473]! } - public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3474]! } - public var Contacts_PermissionsText: String { return self._s[3475]! } - public var Group_Setup_HistoryVisible: String { return self._s[3476]! } - public var Wallet_Month_ShortDecember: String { return self._s[3478]! } - public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3479]! } - public var Passport_Address_AddRentalAgreement: String { return self._s[3480]! } - public var SocksProxySetup_Title: String { return self._s[3481]! } - public var Notification_Mute1h: String { return self._s[3482]! } + public var GroupInfo_InviteLink_ShareLink: String { return self._s[3479]! } + public var StickerPack_Share: String { return self._s[3480]! } + public var Passport_DeleteAddress: String { return self._s[3481]! } + public var Settings_Passport: String { return self._s[3482]! } + public var SharedMedia_EmptyFilesText: String { return self._s[3483]! } + public var Conversation_DeleteMessagesForMe: String { return self._s[3484]! } + public var PasscodeSettings_AutoLock_IfAwayFor_1hour: String { return self._s[3485]! } + public var Contacts_PermissionsText: String { return self._s[3486]! } + public var Group_Setup_HistoryVisible: String { return self._s[3487]! } + public var Wallet_Month_ShortDecember: String { return self._s[3489]! } + public var Channel_EditAdmin_PermissionEnabledByDefault: String { return self._s[3490]! } + public var Passport_Address_AddRentalAgreement: String { return self._s[3491]! } + public var SocksProxySetup_Title: String { return self._s[3492]! } + public var Notification_Mute1h: String { return self._s[3493]! } public func Passport_Email_CodeHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3483]!, self._r[3483]!, [_0]) + return formatWithArgumentRanges(self._s[3494]!, self._r[3494]!, [_0]) } - public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3484]! } + public var NotificationSettings_ShowNotificationsAllAccountsInfoOff: String { return self._s[3495]! } public func PUSH_PINNED_GEOLIVE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3485]!, self._r[3485]!, [_1]) + return formatWithArgumentRanges(self._s[3496]!, self._r[3496]!, [_1]) } - public var FastTwoStepSetup_PasswordSection: String { return self._s[3486]! } - public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3489]! } - public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3491]! } - public var DialogList_NoMessagesText: String { return self._s[3492]! } - public var Privacy_ContactsResetConfirmation: String { return self._s[3493]! } - public var Privacy_Calls_P2PHelp: String { return self._s[3494]! } - public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3496]! } - public var Your_cards_expiration_year_is_invalid: String { return self._s[3497]! } - public var Common_TakePhotoOrVideo: String { return self._s[3498]! } - public var Wallet_Words_Text: String { return self._s[3499]! } - public var Call_StatusBusy: String { return self._s[3500]! } - public var Conversation_PinnedMessage: String { return self._s[3501]! } - public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3502]! } - public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3503]! } - public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3504]! } - public var Undo_ChatCleared: String { return self._s[3505]! } - public var AppleWatch_ReplyPresets: String { return self._s[3506]! } - public var Passport_DiscardMessageDescription: String { return self._s[3508]! } - public var Login_NetworkError: String { return self._s[3509]! } + public var FastTwoStepSetup_PasswordSection: String { return self._s[3497]! } + public var NetworkUsageSettings_ResetStatsConfirmation: String { return self._s[3500]! } + public var InfoPlist_NSFaceIDUsageDescription: String { return self._s[3502]! } + public var DialogList_NoMessagesText: String { return self._s[3503]! } + public var Privacy_ContactsResetConfirmation: String { return self._s[3504]! } + public var Privacy_Calls_P2PHelp: String { return self._s[3505]! } + public var Channel_DiscussionGroup_SearchPlaceholder: String { return self._s[3507]! } + public var Your_cards_expiration_year_is_invalid: String { return self._s[3508]! } + public var Common_TakePhotoOrVideo: String { return self._s[3509]! } + public var Wallet_Words_Text: String { return self._s[3510]! } + public var Call_StatusBusy: String { return self._s[3511]! } + public var Conversation_PinnedMessage: String { return self._s[3512]! } + public var AutoDownloadSettings_VoiceMessagesTitle: String { return self._s[3513]! } + public var Wallet_Configuration_BlockchainNameChangedProceed: String { return self._s[3514]! } + public var TwoStepAuth_SetupPasswordConfirmFailed: String { return self._s[3515]! } + public var Undo_ChatCleared: String { return self._s[3516]! } + public var AppleWatch_ReplyPresets: String { return self._s[3517]! } + public var Passport_DiscardMessageDescription: String { return self._s[3519]! } + public var Login_NetworkError: String { return self._s[3520]! } public func Notification_PinnedRoundMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3510]!, self._r[3510]!, [_0]) + return formatWithArgumentRanges(self._s[3521]!, self._r[3521]!, [_0]) } public func Channel_AdminLog_MessageRemovedChannelUsername(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3511]!, self._r[3511]!, [_0]) + return formatWithArgumentRanges(self._s[3522]!, self._r[3522]!, [_0]) } - public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3512]! } - public var Wallet_WordCheck_ViewWords: String { return self._s[3514]! } - public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3515]! } + public var SocksProxySetup_PasswordPlaceholder: String { return self._s[3523]! } + public var Wallet_WordCheck_ViewWords: String { return self._s[3525]! } + public var Login_ResetAccountProtected_LimitExceeded: String { return self._s[3526]! } public func Watch_LastSeen_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3517]!, self._r[3517]!, [_0]) + return formatWithArgumentRanges(self._s[3528]!, self._r[3528]!, [_0]) } - public var Call_ConnectionErrorMessage: String { return self._s[3518]! } - public var VoiceOver_Chat_Music: String { return self._s[3519]! } - public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3520]! } - public var Compose_GroupTokenListPlaceholder: String { return self._s[3522]! } - public var ConversationMedia_Title: String { return self._s[3523]! } - public var EncryptionKey_Title: String { return self._s[3525]! } - public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3526]! } - public var Notification_Exceptions_AddException: String { return self._s[3527]! } - public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3528]! } - public var Profile_MessageLifetime1m: String { return self._s[3529]! } + public var Call_ConnectionErrorMessage: String { return self._s[3529]! } + public var VoiceOver_Chat_Music: String { return self._s[3530]! } + public var SettingsSearch_Synonyms_Notifications_MessageNotificationsSound: String { return self._s[3531]! } + public var Compose_GroupTokenListPlaceholder: String { return self._s[3533]! } + public var ConversationMedia_Title: String { return self._s[3534]! } + public var EncryptionKey_Title: String { return self._s[3536]! } + public var TwoStepAuth_EnterPasswordTitle: String { return self._s[3537]! } + public var Notification_Exceptions_AddException: String { return self._s[3538]! } + public var PrivacySettings_BlockedPeersEmpty: String { return self._s[3539]! } + public var Profile_MessageLifetime1m: String { return self._s[3540]! } public func Channel_AdminLog_MessageUnkickedName(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3530]!, self._r[3530]!, [_1]) + return formatWithArgumentRanges(self._s[3541]!, self._r[3541]!, [_1]) } - public var Month_GenMay: String { return self._s[3531]! } + public var Month_GenMay: String { return self._s[3542]! } public func LiveLocationUpdated_TodayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3532]!, self._r[3532]!, [_0]) + return formatWithArgumentRanges(self._s[3543]!, self._r[3543]!, [_0]) } - public var PeopleNearby_Users: String { return self._s[3533]! } - public var Wallet_Send_AddressInfo: String { return self._s[3534]! } - public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3535]! } - public var AutoDownloadSettings_ResetSettings: String { return self._s[3536]! } + public var PeopleNearby_Users: String { return self._s[3544]! } + public var Wallet_Send_AddressInfo: String { return self._s[3545]! } + public var ChannelMembers_WhoCanAddMembersAllHelp: String { return self._s[3546]! } + public var AutoDownloadSettings_ResetSettings: String { return self._s[3547]! } public func Wallet_Updated_AtDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3538]!, self._r[3538]!, [_0]) + return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_0]) } - public var Conversation_EmptyPlaceholder: String { return self._s[3539]! } - public var Passport_Address_AddPassportRegistration: String { return self._s[3540]! } - public var Notifications_ChannelNotificationsAlert: String { return self._s[3541]! } - public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3542]! } - public var Camera_TapAndHoldForVideo: String { return self._s[3543]! } - public var Channel_JoinChannel: String { return self._s[3545]! } - public var Appearance_Animations: String { return self._s[3548]! } + public var Conversation_EmptyPlaceholder: String { return self._s[3550]! } + public var Passport_Address_AddPassportRegistration: String { return self._s[3551]! } + public var Notifications_ChannelNotificationsAlert: String { return self._s[3552]! } + public var ChatSettings_AutoDownloadUsingCellular: String { return self._s[3553]! } + public var Camera_TapAndHoldForVideo: String { return self._s[3554]! } + public var Channel_JoinChannel: String { return self._s[3556]! } + public var Appearance_Animations: String { return self._s[3559]! } public func Notification_MessageLifetimeChanged(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3549]!, self._r[3549]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3560]!, self._r[3560]!, [_1, _2]) } - public var Stickers_GroupStickers: String { return self._s[3551]! } - public var Appearance_ShareTheme: String { return self._s[3552]! } - public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3553]! } - public var ConvertToSupergroup_HelpTitle: String { return self._s[3555]! } - public var StickerPackActionInfo_RemovedTitle: String { return self._s[3556]! } - public var Passport_Address_Street: String { return self._s[3557]! } - public var Conversation_AddContact: String { return self._s[3558]! } - public var Login_PhonePlaceholder: String { return self._s[3559]! } - public var Channel_Members_InviteLink: String { return self._s[3561]! } - public var Bot_Stop: String { return self._s[3562]! } - public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3564]! } - public var Notification_PassportValueAddress: String { return self._s[3565]! } - public var Month_ShortJuly: String { return self._s[3566]! } - public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3567]! } - public var Channel_AdminLog_BanSendMedia: String { return self._s[3568]! } - public var Passport_Identity_ReverseSide: String { return self._s[3569]! } - public var Watch_Stickers_Recents: String { return self._s[3572]! } - public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3574]! } - public var Map_SendThisLocation: String { return self._s[3575]! } + public var Stickers_GroupStickers: String { return self._s[3562]! } + public var Appearance_ShareTheme: String { return self._s[3563]! } + public var TwoFactorSetup_Hint_Placeholder: String { return self._s[3564]! } + public var ConvertToSupergroup_HelpTitle: String { return self._s[3566]! } + public var StickerPackActionInfo_RemovedTitle: String { return self._s[3567]! } + public var Passport_Address_Street: String { return self._s[3568]! } + public var Conversation_AddContact: String { return self._s[3569]! } + public var Login_PhonePlaceholder: String { return self._s[3570]! } + public var Channel_Members_InviteLink: String { return self._s[3572]! } + public var Bot_Stop: String { return self._s[3573]! } + public var SettingsSearch_Synonyms_Proxy_UseForCalls: String { return self._s[3575]! } + public var Notification_PassportValueAddress: String { return self._s[3576]! } + public var Month_ShortJuly: String { return self._s[3577]! } + public var Passport_Address_TypeTemporaryRegistrationUploadScan: String { return self._s[3578]! } + public var Channel_AdminLog_BanSendMedia: String { return self._s[3579]! } + public var Passport_Identity_ReverseSide: String { return self._s[3580]! } + public var Watch_Stickers_Recents: String { return self._s[3583]! } + public var PrivacyLastSeenSettings_EmpryUsersPlaceholder: String { return self._s[3585]! } + public var Map_SendThisLocation: String { return self._s[3586]! } public func Time_MonthOfYear_m1(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3576]!, self._r[3576]!, [_0]) + return formatWithArgumentRanges(self._s[3587]!, self._r[3587]!, [_0]) } public func InviteText_SingleContact(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3577]!, self._r[3577]!, [_0]) + return formatWithArgumentRanges(self._s[3588]!, self._r[3588]!, [_0]) } - public var ConvertToSupergroup_Note: String { return self._s[3578]! } - public var Wallet_Intro_NotNow: String { return self._s[3579]! } + public var ConvertToSupergroup_Note: String { return self._s[3589]! } + public var Wallet_Intro_NotNow: String { return self._s[3590]! } public func FileSize_MB(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3580]!, self._r[3580]!, [_0]) + return formatWithArgumentRanges(self._s[3591]!, self._r[3591]!, [_0]) } - public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3581]! } + public var NetworkUsageSettings_GeneralDataSection: String { return self._s[3592]! } public func Compatibility_SecretMediaVersionTooLow(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3582]!, self._r[3582]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3593]!, self._r[3593]!, [_0, _1]) } - public var Login_CallRequestState3: String { return self._s[3584]! } - public var Wallpaper_SearchShort: String { return self._s[3585]! } - public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3587]! } - public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3588]! } - public var Channel_BotDoesntSupportGroups: String { return self._s[3589]! } + public var Login_CallRequestState3: String { return self._s[3595]! } + public var Wallpaper_SearchShort: String { return self._s[3596]! } + public var SettingsSearch_Synonyms_Appearance_ColorTheme: String { return self._s[3598]! } + public var PasscodeSettings_UnlockWithFaceId: String { return self._s[3599]! } + public var Channel_BotDoesntSupportGroups: String { return self._s[3600]! } public func PUSH_CHAT_MESSAGE_GEOLIVE(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3590]!, self._r[3590]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3601]!, self._r[3601]!, [_1, _2]) } - public var Channel_AdminLogFilter_Title: String { return self._s[3591]! } - public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3593]! } - public var Notifications_GroupNotificationsExceptions: String { return self._s[3596]! } + public var Channel_AdminLogFilter_Title: String { return self._s[3602]! } + public var Appearance_ThemePreview_Chat_4_Text: String { return self._s[3604]! } + public var Notifications_GroupNotificationsExceptions: String { return self._s[3607]! } public func FileSize_B(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3597]!, self._r[3597]!, [_0]) + return formatWithArgumentRanges(self._s[3608]!, self._r[3608]!, [_0]) } - public var Passport_CorrectErrors: String { return self._s[3598]! } - public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3599]! } + public var Passport_CorrectErrors: String { return self._s[3609]! } + public var VoiceOver_Chat_YourAnonymousPoll: String { return self._s[3610]! } public func Channel_MessageTitleUpdated(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3600]!, self._r[3600]!, [_0]) + return formatWithArgumentRanges(self._s[3611]!, self._r[3611]!, [_0]) } - public var Map_SendMyCurrentLocation: String { return self._s[3601]! } - public var Channel_DiscussionGroup: String { return self._s[3602]! } - public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3603]! } + public var Map_SendMyCurrentLocation: String { return self._s[3612]! } + public var Channel_DiscussionGroup: String { return self._s[3613]! } + public var TwoFactorSetup_Email_SkipConfirmationSkip: String { return self._s[3614]! } public func PUSH_PINNED_CONTACT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3604]!, self._r[3604]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3615]!, self._r[3615]!, [_1, _2]) } - public var SharedMedia_SearchNoResults: String { return self._s[3605]! } - public var Permissions_NotificationsText_v0: String { return self._s[3606]! } - public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3607]! } - public var Appearance_AppIcon: String { return self._s[3608]! } - public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3609]! } - public var LoginPassword_FloodError: String { return self._s[3610]! } - public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3612]! } - public var Group_Setup_HistoryHiddenHelp: String { return self._s[3613]! } + public var SharedMedia_SearchNoResults: String { return self._s[3616]! } + public var Permissions_NotificationsText_v0: String { return self._s[3617]! } + public var Channel_EditAdmin_PermissionDeleteMessagesOfOthers: String { return self._s[3618]! } + public var Appearance_AppIcon: String { return self._s[3619]! } + public var Appearance_ThemePreview_ChatList_3_AuthorName: String { return self._s[3620]! } + public var LoginPassword_FloodError: String { return self._s[3621]! } + public var Wallet_Send_OwnAddressAlertProceed: String { return self._s[3623]! } + public var Group_Setup_HistoryHiddenHelp: String { return self._s[3624]! } public func TwoStepAuth_PendingEmailHelp(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3614]!, self._r[3614]!, [_0]) + return formatWithArgumentRanges(self._s[3625]!, self._r[3625]!, [_0]) } - public var Passport_Language_bn: String { return self._s[3615]! } + public var Passport_Language_bn: String { return self._s[3626]! } public func DialogList_SingleUploadingPhotoSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3616]!, self._r[3616]!, [_0]) + return formatWithArgumentRanges(self._s[3627]!, self._r[3627]!, [_0]) } - public var ChatList_Context_Pin: String { return self._s[3617]! } + public var ChatList_Context_Pin: String { return self._s[3628]! } public func Notification_PinnedAudioMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3618]!, self._r[3618]!, [_0]) + return formatWithArgumentRanges(self._s[3629]!, self._r[3629]!, [_0]) } public func Channel_AdminLog_MessageChangedGroupStickerPack(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3619]!, self._r[3619]!, [_0]) + return formatWithArgumentRanges(self._s[3630]!, self._r[3630]!, [_0]) } - public var Wallet_Navigation_Close: String { return self._s[3620]! } - public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3624]! } - public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3626]! } - public var Wallet_Month_GenDecember: String { return self._s[3627]! } - public var Contacts_PermissionsAllow: String { return self._s[3628]! } - public var ReportPeer_ReasonCopyright: String { return self._s[3629]! } - public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3630]! } - public var WallpaperPreview_Pattern: String { return self._s[3631]! } - public var Paint_Duplicate: String { return self._s[3632]! } - public var Passport_Address_Country: String { return self._s[3633]! } - public var Notification_RenamedChannel: String { return self._s[3635]! } - public var ChatList_Context_Unmute: String { return self._s[3636]! } - public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3637]! } - public var Group_MessagePhotoUpdated: String { return self._s[3638]! } - public var Channel_BanUser_PermissionSendMedia: String { return self._s[3639]! } - public var Conversation_ContextMenuBan: String { return self._s[3640]! } - public var TwoStepAuth_EmailSent: String { return self._s[3641]! } - public var MessagePoll_NoVotes: String { return self._s[3642]! } - public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3643]! } - public var Passport_Language_is: String { return self._s[3645]! } - public var PeopleNearby_UsersEmpty: String { return self._s[3647]! } - public var Tour_Text5: String { return self._s[3648]! } + public var Wallet_Navigation_Close: String { return self._s[3631]! } + public var GroupInfo_InvitationLinkGroupFull: String { return self._s[3635]! } + public var Group_EditAdmin_PermissionChangeInfo: String { return self._s[3637]! } + public var Wallet_Month_GenDecember: String { return self._s[3638]! } + public var Contacts_PermissionsAllow: String { return self._s[3639]! } + public var ReportPeer_ReasonCopyright: String { return self._s[3640]! } + public var Channel_EditAdmin_PermissinAddAdminOn: String { return self._s[3641]! } + public var WallpaperPreview_Pattern: String { return self._s[3642]! } + public var Paint_Duplicate: String { return self._s[3643]! } + public var Passport_Address_Country: String { return self._s[3644]! } + public var Notification_RenamedChannel: String { return self._s[3646]! } + public var ChatList_Context_Unmute: String { return self._s[3647]! } + public var CheckoutInfo_ErrorPostcodeInvalid: String { return self._s[3648]! } + public var Group_MessagePhotoUpdated: String { return self._s[3649]! } + public var Channel_BanUser_PermissionSendMedia: String { return self._s[3650]! } + public var Conversation_ContextMenuBan: String { return self._s[3651]! } + public var TwoStepAuth_EmailSent: String { return self._s[3652]! } + public var MessagePoll_NoVotes: String { return self._s[3653]! } + public var Wallet_Send_ErrorNotEnoughFundsTitle: String { return self._s[3654]! } + public var Passport_Language_is: String { return self._s[3656]! } + public var PeopleNearby_UsersEmpty: String { return self._s[3658]! } + public var Tour_Text5: String { return self._s[3659]! } public func Call_GroupFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3651]!, self._r[3651]!, [_1, _2]) + return formatWithArgumentRanges(self._s[3662]!, self._r[3662]!, [_1, _2]) } - public var Undo_SecretChatDeleted: String { return self._s[3652]! } - public var SocksProxySetup_ShareQRCode: String { return self._s[3653]! } + public var Undo_SecretChatDeleted: String { return self._s[3663]! } + public var SocksProxySetup_ShareQRCode: String { return self._s[3664]! } public func VoiceOver_Chat_Size(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3654]!, self._r[3654]!, [_0]) + return formatWithArgumentRanges(self._s[3665]!, self._r[3665]!, [_0]) } - public var Forward_ErrorDisabledForChat: String { return self._s[3655]! } - public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3656]! } - public var Paint_Edit: String { return self._s[3658]! } - public var ScheduledMessages_ReminderNotification: String { return self._s[3660]! } - public var Undo_DeletedGroup: String { return self._s[3662]! } - public var LoginPassword_ForgotPassword: String { return self._s[3663]! } - public var Wallet_WordImport_IncorrectTitle: String { return self._s[3664]! } - public var GroupInfo_GroupNamePlaceholder: String { return self._s[3665]! } + public var Forward_ErrorDisabledForChat: String { return self._s[3666]! } + public var LogoutOptions_ChangePhoneNumberText: String { return self._s[3667]! } + public var Paint_Edit: String { return self._s[3669]! } + public var ScheduledMessages_ReminderNotification: String { return self._s[3671]! } + public var Undo_DeletedGroup: String { return self._s[3673]! } + public var LoginPassword_ForgotPassword: String { return self._s[3674]! } + public var Wallet_WordImport_IncorrectTitle: String { return self._s[3675]! } + public var GroupInfo_GroupNamePlaceholder: String { return self._s[3676]! } public func Notification_Kicked(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3666]!, self._r[3666]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3677]!, self._r[3677]!, [_0, _1]) } - public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3667]! } - public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3668]! } - public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3669]! } - public var Passport_Language_uz: String { return self._s[3670]! } - public var Conversation_PinMessageAlertGroup: String { return self._s[3671]! } - public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3672]! } - public var Map_StopLiveLocation: String { return self._s[3674]! } - public var VoiceOver_MessageContextSend: String { return self._s[3676]! } - public var PasscodeSettings_Help: String { return self._s[3677]! } - public var NotificationsSound_Input: String { return self._s[3678]! } - public var Share_Title: String { return self._s[3681]! } - public var LogoutOptions_Title: String { return self._s[3682]! } - public var Wallet_Send_AddressText: String { return self._s[3683]! } - public var Login_TermsOfServiceAgree: String { return self._s[3684]! } - public var Compose_NewEncryptedChatTitle: String { return self._s[3685]! } - public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3686]! } - public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3687]! } - public var EnterPasscode_EnterTitle: String { return self._s[3688]! } + public var AppWallet_TransactionInfo_FeeInfoURL: String { return self._s[3678]! } + public var Conversation_InputTextCaptionPlaceholder: String { return self._s[3679]! } + public var AutoDownloadSettings_VideoMessagesTitle: String { return self._s[3680]! } + public var Passport_Language_uz: String { return self._s[3681]! } + public var Conversation_PinMessageAlertGroup: String { return self._s[3682]! } + public var SettingsSearch_Synonyms_Privacy_GroupsAndChannels: String { return self._s[3683]! } + public var Map_StopLiveLocation: String { return self._s[3685]! } + public var VoiceOver_MessageContextSend: String { return self._s[3687]! } + public var PasscodeSettings_Help: String { return self._s[3688]! } + public var NotificationsSound_Input: String { return self._s[3689]! } + public var Share_Title: String { return self._s[3692]! } + public var LogoutOptions_Title: String { return self._s[3693]! } + public var Wallet_Send_AddressText: String { return self._s[3694]! } + public var Login_TermsOfServiceAgree: String { return self._s[3695]! } + public var Compose_NewEncryptedChatTitle: String { return self._s[3696]! } + public var Channel_AdminLog_TitleSelectedEvents: String { return self._s[3697]! } + public var Channel_EditAdmin_PermissionEditMessages: String { return self._s[3698]! } + public var EnterPasscode_EnterTitle: String { return self._s[3699]! } public func Call_PrivacyErrorMessage(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3689]!, self._r[3689]!, [_0]) + return formatWithArgumentRanges(self._s[3700]!, self._r[3700]!, [_0]) } - public var Settings_CopyPhoneNumber: String { return self._s[3690]! } - public var Conversation_AddToContacts: String { return self._s[3691]! } + public var Settings_CopyPhoneNumber: String { return self._s[3701]! } + public var Conversation_AddToContacts: String { return self._s[3702]! } public func VoiceOver_Chat_ReplyFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3692]!, self._r[3692]!, [_0]) - } - public var NotificationsSound_Keys: String { return self._s[3693]! } - public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3694]!, self._r[3694]!, [_0]) - } - public var Notification_MessageLifetime1w: String { return self._s[3695]! } - public var Message_Video: String { return self._s[3696]! } - public var AutoDownloadSettings_CellularTitle: String { return self._s[3697]! } - public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3698]!, self._r[3698]!, [_1]) - } - public var Wallet_Receive_AmountInfo: String { return self._s[3701]! } - public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3702]!, self._r[3702]!, [_0]) - } - public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[3703]!, self._r[3703]!, [_0]) } - public var Passport_Language_mk: String { return self._s[3704]! } - public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_1, _2, _3]) + public var NotificationsSound_Keys: String { return self._s[3704]! } + public func Call_ParticipantVersionOutdatedError(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3705]!, self._r[3705]!, [_0]) } - public var CreatePoll_CancelConfirmation: String { return self._s[3706]! } - public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3707]! } - public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3709]! } - public var PrivacyPolicy_Decline: String { return self._s[3710]! } - public var Passport_Identity_DoesNotExpire: String { return self._s[3711]! } - public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3712]! } - public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3713]! } - public var Permissions_SiriAllow_v0: String { return self._s[3715]! } - public var Wallet_Month_ShortAugust: String { return self._s[3716]! } - public var Appearance_ThemeCarouselNight: String { return self._s[3717]! } + public var Notification_MessageLifetime1w: String { return self._s[3706]! } + public var Message_Video: String { return self._s[3707]! } + public var AutoDownloadSettings_CellularTitle: String { return self._s[3708]! } + public func PUSH_CHANNEL_MESSAGE_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3709]!, self._r[3709]!, [_1]) + } + public var Wallet_Receive_AmountInfo: String { return self._s[3712]! } + public func Notification_JoinedChat(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3713]!, self._r[3713]!, [_0]) + } + public func PrivacySettings_LastSeenContactsPlus(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3714]!, self._r[3714]!, [_0]) + } + public var Passport_Language_mk: String { return self._s[3715]! } + public func Wallet_Time_PreciseDate_m2(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[3716]!, self._r[3716]!, [_1, _2, _3]) + } + public var CreatePoll_CancelConfirmation: String { return self._s[3717]! } + public var MessagePoll_LabelAnonymousQuiz: String { return self._s[3718]! } + public var Conversation_SilentBroadcastTooltipOn: String { return self._s[3720]! } + public var PrivacyPolicy_Decline: String { return self._s[3721]! } + public var Passport_Identity_DoesNotExpire: String { return self._s[3722]! } + public var Channel_AdminLogFilter_EventsRestrictions: String { return self._s[3723]! } + public var AuthSessions_AddDeviceIntro_Action: String { return self._s[3724]! } + public var Permissions_SiriAllow_v0: String { return self._s[3726]! } + public var Wallet_Month_ShortAugust: String { return self._s[3727]! } + public var Appearance_ThemeCarouselNight: String { return self._s[3728]! } public func LOCAL_CHAT_MESSAGE_FWDS(_ _1: String, _ _2: Int) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3718]!, self._r[3718]!, [_1, "\(_2)"]) + return formatWithArgumentRanges(self._s[3729]!, self._r[3729]!, [_1, "\(_2)"]) } public func Notification_RenamedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3719]!, self._r[3719]!, [_0]) + return formatWithArgumentRanges(self._s[3730]!, self._r[3730]!, [_0]) } - public var Paint_Regular: String { return self._s[3720]! } - public var ChatSettings_AutoDownloadReset: String { return self._s[3721]! } - public var SocksProxySetup_ShareLink: String { return self._s[3722]! } - public var Wallet_Qr_Title: String { return self._s[3723]! } - public var BlockedUsers_SelectUserTitle: String { return self._s[3724]! } - public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3726]! } - public var Wallet_Settings_Configuration: String { return self._s[3727]! } - public var GroupInfo_InviteByLink: String { return self._s[3728]! } - public var MessageTimer_Custom: String { return self._s[3729]! } - public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3730]! } - public var Conversation_StopQuizConfirmationTitle: String { return self._s[3731]! } - public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3733]! } - public var Conversation_SendMessage_SetReminder: String { return self._s[3734]! } - public var VoiceOver_Chat_Selected: String { return self._s[3735]! } - public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3736]! } - public var Channel_Username_InvalidTaken: String { return self._s[3737]! } - public var Conversation_ClousStorageInfo_Description3: String { return self._s[3738]! } - public var Wallet_WordCheck_TryAgain: String { return self._s[3739]! } - public var Wallet_Info_TransactionPendingHeader: String { return self._s[3740]! } - public var Settings_ChatBackground: String { return self._s[3741]! } - public var Channel_Subscribers_Title: String { return self._s[3742]! } - public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3743]! } - public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3744]! } - public var Watch_ConnectionDescription: String { return self._s[3745]! } - public var OldChannels_NoticeText: String { return self._s[3748]! } - public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3749]! } - public var IntentsSettings_SuggestBy: String { return self._s[3751]! } - public var Theme_ThemeChangedText: String { return self._s[3752]! } - public var ChatList_ArchivedChatsTitle: String { return self._s[3753]! } - public var Wallpaper_ResetWallpapers: String { return self._s[3754]! } - public var Wallet_Send_TransactionInProgress: String { return self._s[3755]! } - public var EditProfile_Title: String { return self._s[3756]! } - public var NotificationsSound_Bamboo: String { return self._s[3758]! } - public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3760]! } - public var Login_SmsRequestState2: String { return self._s[3761]! } - public var Passport_Language_ar: String { return self._s[3762]! } + public var Paint_Regular: String { return self._s[3731]! } + public var ChatSettings_AutoDownloadReset: String { return self._s[3732]! } + public var SocksProxySetup_ShareLink: String { return self._s[3733]! } + public var Wallet_Qr_Title: String { return self._s[3734]! } + public var BlockedUsers_SelectUserTitle: String { return self._s[3735]! } + public var VoiceOver_Chat_RecordModeVoiceMessage: String { return self._s[3737]! } + public var Wallet_Settings_Configuration: String { return self._s[3738]! } + public var GroupInfo_InviteByLink: String { return self._s[3739]! } + public var MessageTimer_Custom: String { return self._s[3740]! } + public var UserInfo_NotificationsDefaultEnabled: String { return self._s[3741]! } + public var Conversation_StopQuizConfirmationTitle: String { return self._s[3742]! } + public var Passport_Address_TypeTemporaryRegistration: String { return self._s[3744]! } + public var Conversation_SendMessage_SetReminder: String { return self._s[3745]! } + public var VoiceOver_Chat_Selected: String { return self._s[3746]! } + public var ChatSettings_AutoDownloadUsingWiFi: String { return self._s[3747]! } + public var Channel_Username_InvalidTaken: String { return self._s[3748]! } + public var Conversation_ClousStorageInfo_Description3: String { return self._s[3749]! } + public var Wallet_WordCheck_TryAgain: String { return self._s[3750]! } + public var Wallet_Info_TransactionPendingHeader: String { return self._s[3751]! } + public var Settings_ChatBackground: String { return self._s[3752]! } + public var Channel_Subscribers_Title: String { return self._s[3753]! } + public var Wallet_Receive_InvoiceUrlHeader: String { return self._s[3754]! } + public var ApplyLanguage_ChangeLanguageTitle: String { return self._s[3755]! } + public var Watch_ConnectionDescription: String { return self._s[3756]! } + public var OldChannels_NoticeText: String { return self._s[3759]! } + public var Wallet_Configuration_ApplyErrorTitle: String { return self._s[3760]! } + public var IntentsSettings_SuggestBy: String { return self._s[3762]! } + public var Theme_ThemeChangedText: String { return self._s[3763]! } + public var ChatList_ArchivedChatsTitle: String { return self._s[3764]! } + public var Wallpaper_ResetWallpapers: String { return self._s[3765]! } + public var Wallet_Send_TransactionInProgress: String { return self._s[3766]! } + public var EditProfile_Title: String { return self._s[3767]! } + public var NotificationsSound_Bamboo: String { return self._s[3769]! } + public var Channel_AdminLog_MessagePreviousMessage: String { return self._s[3771]! } + public var Login_SmsRequestState2: String { return self._s[3772]! } + public var Passport_Language_ar: String { return self._s[3773]! } public func Message_AuthorPinnedGame(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3763]!, self._r[3763]!, [_0]) + return formatWithArgumentRanges(self._s[3774]!, self._r[3774]!, [_0]) } - public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3764]! } - public var Wallet_Created_Text: String { return self._s[3765]! } - public var Conversation_MessageDialogEdit: String { return self._s[3767]! } - public var Wallet_Created_Proceed: String { return self._s[3768]! } - public var Wallet_Words_Done: String { return self._s[3769]! } - public var VoiceOver_Media_PlaybackPause: String { return self._s[3770]! } + public var SettingsSearch_Synonyms_EditProfile_Title: String { return self._s[3775]! } + public var Wallet_Created_Text: String { return self._s[3776]! } + public var Conversation_MessageDialogEdit: String { return self._s[3778]! } + public var Wallet_Created_Proceed: String { return self._s[3779]! } + public var Wallet_Words_Done: String { return self._s[3780]! } + public var VoiceOver_Media_PlaybackPause: String { return self._s[3781]! } public func PUSH_AUTH_UNKNOWN(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3771]!, self._r[3771]!, [_1]) + return formatWithArgumentRanges(self._s[3782]!, self._r[3782]!, [_1]) } - public var Common_Close: String { return self._s[3772]! } - public var GroupInfo_PublicLink: String { return self._s[3773]! } - public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3774]! } - public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3775]! } + public var Common_Close: String { return self._s[3783]! } + public var GroupInfo_PublicLink: String { return self._s[3784]! } + public var Channel_OwnershipTransfer_ErrorPrivacyRestricted: String { return self._s[3785]! } + public var SettingsSearch_Synonyms_Notifications_GroupNotificationsPreview: String { return self._s[3786]! } public func Channel_AdminLog_MessageToggleInvitesOff(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3779]!, self._r[3779]!, [_0]) + return formatWithArgumentRanges(self._s[3790]!, self._r[3790]!, [_0]) } - public var UserInfo_About_Placeholder: String { return self._s[3780]! } + public var UserInfo_About_Placeholder: String { return self._s[3791]! } public func Conversation_FileHowToText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3781]!, self._r[3781]!, [_0]) + return formatWithArgumentRanges(self._s[3792]!, self._r[3792]!, [_0]) } - public var GroupInfo_Permissions_SectionTitle: String { return self._s[3782]! } - public var Channel_Info_Banned: String { return self._s[3784]! } + public var GroupInfo_Permissions_SectionTitle: String { return self._s[3793]! } + public var Channel_Info_Banned: String { return self._s[3795]! } public func Time_MonthOfYear_m11(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3785]!, self._r[3785]!, [_0]) + return formatWithArgumentRanges(self._s[3796]!, self._r[3796]!, [_0]) } - public var Appearance_Other: String { return self._s[3786]! } - public var Passport_Language_my: String { return self._s[3787]! } - public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3788]! } + public var Appearance_Other: String { return self._s[3797]! } + public var Passport_Language_my: String { return self._s[3798]! } + public var Group_Setup_BasicHistoryHiddenHelp: String { return self._s[3799]! } public func Time_PreciseDate_m9(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3789]!, self._r[3789]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3800]!, self._r[3800]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3790]! } - public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3791]! } - public var Preview_CopyAddress: String { return self._s[3792]! } + public var SettingsSearch_Synonyms_Privacy_PasscodeAndFaceId: String { return self._s[3801]! } + public var IntentsSettings_SuggestedAndSpotlightChatsInfo: String { return self._s[3802]! } + public var Preview_CopyAddress: String { return self._s[3803]! } public func DialogList_SinglePlayingGameSuffix(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3793]!, self._r[3793]!, [_0]) + return formatWithArgumentRanges(self._s[3804]!, self._r[3804]!, [_0]) } - public var KeyCommand_JumpToPreviousChat: String { return self._s[3794]! } - public var UserInfo_BotSettings: String { return self._s[3795]! } - public var LiveLocation_MenuStopAll: String { return self._s[3797]! } - public var Passport_PasswordCreate: String { return self._s[3798]! } - public var StickerSettings_MaskContextInfo: String { return self._s[3799]! } - public var Message_PinnedLocationMessage: String { return self._s[3800]! } - public var Map_Satellite: String { return self._s[3801]! } - public var Watch_Message_Unsupported: String { return self._s[3802]! } - public var Username_TooManyPublicUsernamesError: String { return self._s[3803]! } - public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3804]! } + public var KeyCommand_JumpToPreviousChat: String { return self._s[3805]! } + public var UserInfo_BotSettings: String { return self._s[3806]! } + public var LiveLocation_MenuStopAll: String { return self._s[3808]! } + public var Passport_PasswordCreate: String { return self._s[3809]! } + public var StickerSettings_MaskContextInfo: String { return self._s[3810]! } + public var Message_PinnedLocationMessage: String { return self._s[3811]! } + public var Map_Satellite: String { return self._s[3812]! } + public var Watch_Message_Unsupported: String { return self._s[3813]! } + public var Username_TooManyPublicUsernamesError: String { return self._s[3814]! } + public var TwoStepAuth_EnterPasswordInvalid: String { return self._s[3815]! } public func Notification_PinnedTextMessage(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3805]!, self._r[3805]!, [_0, _1]) + return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_0, _1]) } public func Conversation_OpenBotLinkText(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3806]!, self._r[3806]!, [_0]) + return formatWithArgumentRanges(self._s[3817]!, self._r[3817]!, [_0]) } - public var Wallet_WordImport_Continue: String { return self._s[3807]! } + public var Wallet_WordImport_Continue: String { return self._s[3818]! } public func TwoFactorSetup_EmailVerification_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3808]!, self._r[3808]!, [_0]) + return formatWithArgumentRanges(self._s[3819]!, self._r[3819]!, [_0]) } - public var Notifications_ChannelNotificationsHelp: String { return self._s[3809]! } - public var Privacy_Calls_P2PContacts: String { return self._s[3810]! } - public var NotificationsSound_None: String { return self._s[3811]! } - public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3812]! } - public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3814]! } - public var AccessDenied_VoiceMicrophone: String { return self._s[3815]! } + public var Notifications_ChannelNotificationsHelp: String { return self._s[3820]! } + public var Privacy_Calls_P2PContacts: String { return self._s[3821]! } + public var NotificationsSound_None: String { return self._s[3822]! } + public var Wallet_TransactionInfo_StorageFeeHeader: String { return self._s[3823]! } + public var Channel_DiscussionGroup_UnlinkGroup: String { return self._s[3825]! } + public var AccessDenied_VoiceMicrophone: String { return self._s[3826]! } public func ApplyLanguage_ChangeLanguageAlreadyActive(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3816]!, self._r[3816]!, [_1]) + return formatWithArgumentRanges(self._s[3827]!, self._r[3827]!, [_1]) } - public var Cache_Indexing: String { return self._s[3817]! } - public var DialogList_RecentTitlePeople: String { return self._s[3819]! } - public var DialogList_EncryptionRejected: String { return self._s[3820]! } - public var GroupInfo_Administrators: String { return self._s[3821]! } - public var Passport_ScanPassportHelp: String { return self._s[3822]! } - public var Application_Name: String { return self._s[3823]! } - public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3824]! } - public var Appearance_ThemeCarouselDay: String { return self._s[3826]! } - public var Passport_Identity_TranslationHelp: String { return self._s[3827]! } + public var Cache_Indexing: String { return self._s[3828]! } + public var DialogList_RecentTitlePeople: String { return self._s[3830]! } + public var DialogList_EncryptionRejected: String { return self._s[3831]! } + public var GroupInfo_Administrators: String { return self._s[3832]! } + public var Passport_ScanPassportHelp: String { return self._s[3833]! } + public var Application_Name: String { return self._s[3834]! } + public var Channel_AdminLogFilter_ChannelEventsInfo: String { return self._s[3835]! } + public var PeopleNearby_MakeVisible: String { return self._s[3837]! } + public var Appearance_ThemeCarouselDay: String { return self._s[3838]! } + public var Passport_Identity_TranslationHelp: String { return self._s[3839]! } public func VoiceOver_Chat_VideoMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3828]!, self._r[3828]!, [_0]) + return formatWithArgumentRanges(self._s[3840]!, self._r[3840]!, [_0]) } public func Notification_JoinedGroupByLink(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3829]!, self._r[3829]!, [_0]) + return formatWithArgumentRanges(self._s[3841]!, self._r[3841]!, [_0]) } public func DialogList_EncryptedChatStartedOutgoing(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3830]!, self._r[3830]!, [_0]) + return formatWithArgumentRanges(self._s[3842]!, self._r[3842]!, [_0]) } - public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3831]! } - public var Privacy_ChatsTitle: String { return self._s[3832]! } - public var DialogList_ClearHistoryConfirmation: String { return self._s[3833]! } - public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3834]! } - public var Watch_Suggestion_HoldOn: String { return self._s[3835]! } - public var Group_EditAdmin_TransferOwnership: String { return self._s[3836]! } - public var WebBrowser_Title: String { return self._s[3837]! } - public var Group_LinkedChannel: String { return self._s[3838]! } - public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3839]! } - public var SocksProxySetup_RequiredCredentials: String { return self._s[3840]! } - public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3841]! } - public var Appearance_TextSize_UseSystem: String { return self._s[3842]! } - public var TwoStepAuth_EmailSkipAlert: String { return self._s[3843]! } - public var ScheduledMessages_RemindersTitle: String { return self._s[3845]! } - public var Channel_Setup_TypePublic: String { return self._s[3847]! } + public var Channel_EditAdmin_PermissionDeleteMessages: String { return self._s[3843]! } + public var Privacy_ChatsTitle: String { return self._s[3844]! } + public var DialogList_ClearHistoryConfirmation: String { return self._s[3845]! } + public var SettingsSearch_Synonyms_Data_Storage_ClearCache: String { return self._s[3846]! } + public var Watch_Suggestion_HoldOn: String { return self._s[3847]! } + public var Group_EditAdmin_TransferOwnership: String { return self._s[3848]! } + public var WebBrowser_Title: String { return self._s[3849]! } + public var Group_LinkedChannel: String { return self._s[3850]! } + public var VoiceOver_Chat_SeenByRecipient: String { return self._s[3851]! } + public var SocksProxySetup_RequiredCredentials: String { return self._s[3852]! } + public var Passport_Address_TypeRentalAgreementUploadScan: String { return self._s[3853]! } + public var Appearance_TextSize_UseSystem: String { return self._s[3854]! } + public var TwoStepAuth_EmailSkipAlert: String { return self._s[3855]! } + public var ScheduledMessages_RemindersTitle: String { return self._s[3857]! } + public var Channel_Setup_TypePublic: String { return self._s[3859]! } public func Channel_AdminLog_MessageToggleInvitesOn(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3848]!, self._r[3848]!, [_0]) + return formatWithArgumentRanges(self._s[3860]!, self._r[3860]!, [_0]) } - public var Channel_TypeSetup_Title: String { return self._s[3850]! } - public var MessagePoll_ViewResults: String { return self._s[3851]! } - public var Map_OpenInMaps: String { return self._s[3853]! } + public var Channel_TypeSetup_Title: String { return self._s[3862]! } + public var MessagePoll_ViewResults: String { return self._s[3863]! } + public var Map_OpenInMaps: String { return self._s[3865]! } public func PUSH_PINNED_NOTEXT(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3854]!, self._r[3854]!, [_1]) + return formatWithArgumentRanges(self._s[3866]!, self._r[3866]!, [_1]) } - public var NotificationsSound_Tremolo: String { return self._s[3856]! } + public var NotificationsSound_Tremolo: String { return self._s[3868]! } public func Date_ChatDateHeaderYear(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3857]!, self._r[3857]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3869]!, self._r[3869]!, [_1, _2, _3]) } - public var ConversationProfile_UnknownAddMemberError: String { return self._s[3858]! } - public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3859]! } - public var Passport_PasswordHelp: String { return self._s[3860]! } - public var Login_CodeExpiredError: String { return self._s[3861]! } - public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3862]! } - public var Conversation_TitleUnmute: String { return self._s[3863]! } - public var Passport_Identity_ScansHelp: String { return self._s[3864]! } - public var Passport_Language_lo: String { return self._s[3865]! } - public var Camera_FlashAuto: String { return self._s[3866]! } - public var Conversation_OpenBotLinkOpen: String { return self._s[3867]! } - public var Common_Cancel: String { return self._s[3868]! } - public var DialogList_SavedMessagesTooltip: String { return self._s[3869]! } - public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3870]! } - public var Appearance_TintAllColors: String { return self._s[3871]! } + public var ConversationProfile_UnknownAddMemberError: String { return self._s[3870]! } + public var Channel_OwnershipTransfer_PasswordPlaceholder: String { return self._s[3871]! } + public var Passport_PasswordHelp: String { return self._s[3872]! } + public var Login_CodeExpiredError: String { return self._s[3873]! } + public var Channel_EditAdmin_PermissionChangeInfo: String { return self._s[3874]! } + public var Conversation_TitleUnmute: String { return self._s[3875]! } + public var Passport_Identity_ScansHelp: String { return self._s[3876]! } + public var Passport_Language_lo: String { return self._s[3877]! } + public var Camera_FlashAuto: String { return self._s[3878]! } + public var Conversation_OpenBotLinkOpen: String { return self._s[3879]! } + public var Common_Cancel: String { return self._s[3880]! } + public var DialogList_SavedMessagesTooltip: String { return self._s[3881]! } + public var TwoStepAuth_SetupPasswordTitle: String { return self._s[3882]! } + public var Appearance_TintAllColors: String { return self._s[3883]! } public func PUSH_MESSAGE_FWD(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3872]!, self._r[3872]!, [_1]) + return formatWithArgumentRanges(self._s[3884]!, self._r[3884]!, [_1]) } - public var Conversation_ReportSpamConfirmation: String { return self._s[3873]! } - public var ChatSettings_Title: String { return self._s[3875]! } - public var Passport_PasswordReset: String { return self._s[3876]! } - public var SocksProxySetup_TypeNone: String { return self._s[3877]! } - public var EditTheme_Title: String { return self._s[3880]! } - public var PhoneNumberHelp_Help: String { return self._s[3881]! } - public var Checkout_EnterPassword: String { return self._s[3882]! } - public var Share_AuthTitle: String { return self._s[3884]! } - public var Activity_UploadingDocument: String { return self._s[3885]! } - public var State_Connecting: String { return self._s[3886]! } - public var Profile_MessageLifetime1w: String { return self._s[3887]! } - public var Conversation_ContextMenuReport: String { return self._s[3888]! } - public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3889]! } - public var AutoNightTheme_ScheduledTo: String { return self._s[3890]! } + public var Conversation_ReportSpamConfirmation: String { return self._s[3885]! } + public var ChatSettings_Title: String { return self._s[3887]! } + public var Passport_PasswordReset: String { return self._s[3888]! } + public var SocksProxySetup_TypeNone: String { return self._s[3889]! } + public var EditTheme_Title: String { return self._s[3892]! } + public var PhoneNumberHelp_Help: String { return self._s[3893]! } + public var Checkout_EnterPassword: String { return self._s[3894]! } + public var Share_AuthTitle: String { return self._s[3896]! } + public var Activity_UploadingDocument: String { return self._s[3897]! } + public var State_Connecting: String { return self._s[3898]! } + public var Profile_MessageLifetime1w: String { return self._s[3899]! } + public var Conversation_ContextMenuReport: String { return self._s[3900]! } + public var CheckoutInfo_ReceiverInfoPhone: String { return self._s[3901]! } + public var AutoNightTheme_ScheduledTo: String { return self._s[3902]! } public func VoiceOver_Chat_AnonymousPollFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3891]!, self._r[3891]!, [_0]) + return formatWithArgumentRanges(self._s[3903]!, self._r[3903]!, [_0]) } - public var AuthSessions_Terminate: String { return self._s[3892]! } - public var Wallet_WordImport_CanNotRemember: String { return self._s[3893]! } - public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3895]! } - public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3896]! } - public var PhotoEditor_Set: String { return self._s[3897]! } - public var EmptyGroupInfo_Title: String { return self._s[3898]! } - public var Login_PadPhoneHelp: String { return self._s[3899]! } - public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3901]! } - public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3903]! } - public var NotificationsSound_Complete: String { return self._s[3904]! } - public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3905]! } - public var Group_Info_AdminLog: String { return self._s[3906]! } - public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3907]! } + public var AuthSessions_Terminate: String { return self._s[3904]! } + public var Wallet_WordImport_CanNotRemember: String { return self._s[3905]! } + public var Checkout_NewCard_CardholderNamePlaceholder: String { return self._s[3907]! } + public var KeyCommand_JumpToPreviousUnreadChat: String { return self._s[3908]! } + public var PhotoEditor_Set: String { return self._s[3909]! } + public var EmptyGroupInfo_Title: String { return self._s[3910]! } + public var Login_PadPhoneHelp: String { return self._s[3911]! } + public var AutoDownloadSettings_TypeGroupChats: String { return self._s[3913]! } + public var PrivacyPolicy_DeclineLastWarning: String { return self._s[3915]! } + public var NotificationsSound_Complete: String { return self._s[3916]! } + public var SettingsSearch_Synonyms_Privacy_Data_Title: String { return self._s[3917]! } + public var Group_Info_AdminLog: String { return self._s[3918]! } + public var GroupPermission_NotAvailableInPublicGroups: String { return self._s[3919]! } public func Wallet_Time_PreciseDate_m11(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3908]!, self._r[3908]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3920]!, self._r[3920]!, [_1, _2, _3]) } - public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3909]! } - public var Group_Location_CreateInThisPlace: String { return self._s[3911]! } - public var Conversation_Admin: String { return self._s[3912]! } - public var Conversation_GifTooltip: String { return self._s[3913]! } - public var Passport_NotLoggedInMessage: String { return self._s[3914]! } + public var Channel_AdminLog_InfoPanelAlertText: String { return self._s[3921]! } + public var Group_Location_CreateInThisPlace: String { return self._s[3923]! } + public var Conversation_Admin: String { return self._s[3924]! } + public var Conversation_GifTooltip: String { return self._s[3925]! } + public var Passport_NotLoggedInMessage: String { return self._s[3926]! } public func AutoDownloadSettings_OnFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3916]!, self._r[3916]!, [_0]) + return formatWithArgumentRanges(self._s[3928]!, self._r[3928]!, [_0]) } - public var Profile_MessageLifetimeForever: String { return self._s[3917]! } - public var SharedMedia_EmptyTitle: String { return self._s[3919]! } - public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3921]! } - public var Username_Help: String { return self._s[3922]! } - public var DialogList_LanguageTooltip: String { return self._s[3924]! } - public var Map_LoadError: String { return self._s[3925]! } - public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3926]! } - public var Channel_AdminLog_AddMembers: String { return self._s[3927]! } - public var ArchivedChats_IntroTitle2: String { return self._s[3928]! } - public var Notification_Exceptions_NewException: String { return self._s[3929]! } - public var TwoStepAuth_EmailTitle: String { return self._s[3930]! } - public var WatchRemote_AlertText: String { return self._s[3931]! } + public var Profile_MessageLifetimeForever: String { return self._s[3929]! } + public var SharedMedia_EmptyTitle: String { return self._s[3931]! } + public var Channel_Edit_PrivatePublicLinkAlert: String { return self._s[3933]! } + public var Username_Help: String { return self._s[3934]! } + public var DialogList_LanguageTooltip: String { return self._s[3936]! } + public var Map_LoadError: String { return self._s[3937]! } + public var Login_PhoneNumberAlreadyAuthorized: String { return self._s[3938]! } + public var Channel_AdminLog_AddMembers: String { return self._s[3939]! } + public var ArchivedChats_IntroTitle2: String { return self._s[3940]! } + public var Notification_Exceptions_NewException: String { return self._s[3941]! } + public var TwoStepAuth_EmailTitle: String { return self._s[3942]! } + public var WatchRemote_AlertText: String { return self._s[3943]! } public func Wallet_Send_ConfirmationText(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3932]!, self._r[3932]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3944]!, self._r[3944]!, [_1, _2, _3]) } - public var ChatSettings_ConnectionType_Title: String { return self._s[3936]! } - public var WebBrowser_DefaultBrowser: String { return self._s[3937]! } + public var ChatSettings_ConnectionType_Title: String { return self._s[3948]! } + public var WebBrowser_DefaultBrowser: String { return self._s[3949]! } public func Settings_CheckPhoneNumberTitle(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3938]!, self._r[3938]!, [_0]) + return formatWithArgumentRanges(self._s[3950]!, self._r[3950]!, [_0]) } - public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3939]! } - public var Passport_Address_CountryPlaceholder: String { return self._s[3940]! } + public var SettingsSearch_Synonyms_Calls_CallTab: String { return self._s[3951]! } + public var Passport_Address_CountryPlaceholder: String { return self._s[3952]! } public func DialogList_AwaitingEncryption(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3941]!, self._r[3941]!, [_0]) + return formatWithArgumentRanges(self._s[3953]!, self._r[3953]!, [_0]) } public func Time_PreciseDate_m6(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3942]!, self._r[3942]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_1, _2, _3]) } - public var Group_AdminLog_EmptyText: String { return self._s[3943]! } - public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3944]! } - public var Conversation_PrivateChannelTooltip: String { return self._s[3946]! } - public var Wallet_Created_ExportErrorText: String { return self._s[3947]! } - public var ChatList_UndoArchiveText1: String { return self._s[3948]! } - public var AccessDenied_VideoMicrophone: String { return self._s[3949]! } - public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3950]! } - public var Cache_ClearNone: String { return self._s[3951]! } - public var SocksProxySetup_FailedToConnect: String { return self._s[3952]! } - public var Permissions_NotificationsTitle_v0: String { return self._s[3953]! } + public var Group_AdminLog_EmptyText: String { return self._s[3955]! } + public var SettingsSearch_Synonyms_Appearance_Title: String { return self._s[3956]! } + public var Conversation_PrivateChannelTooltip: String { return self._s[3958]! } + public var Wallet_Created_ExportErrorText: String { return self._s[3959]! } + public var ChatList_UndoArchiveText1: String { return self._s[3960]! } + public var AccessDenied_VideoMicrophone: String { return self._s[3961]! } + public var Conversation_ContextMenuStickerPackAdd: String { return self._s[3962]! } + public var Cache_ClearNone: String { return self._s[3963]! } + public var SocksProxySetup_FailedToConnect: String { return self._s[3964]! } + public var Permissions_NotificationsTitle_v0: String { return self._s[3965]! } public func Channel_AdminLog_MessageEdited(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3954]!, self._r[3954]!, [_0]) + return formatWithArgumentRanges(self._s[3966]!, self._r[3966]!, [_0]) } - public var Passport_Identity_Country: String { return self._s[3955]! } + public var Passport_Identity_Country: String { return self._s[3967]! } public func ChatSettings_AutoDownloadSettings_TypeFile(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3956]!, self._r[3956]!, [_0]) + return formatWithArgumentRanges(self._s[3968]!, self._r[3968]!, [_0]) } public func Notification_CreatedChat(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3957]!, self._r[3957]!, [_0]) + return formatWithArgumentRanges(self._s[3969]!, self._r[3969]!, [_0]) } - public var Exceptions_AddToExceptions: String { return self._s[3958]! } - public var AccessDenied_Settings: String { return self._s[3959]! } - public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3960]! } - public var Month_ShortMay: String { return self._s[3961]! } - public var Compose_NewGroup: String { return self._s[3963]! } - public var Group_Setup_TypePrivate: String { return self._s[3965]! } - public var Login_PadPhoneHelpTitle: String { return self._s[3967]! } - public var Appearance_ThemeDayClassic: String { return self._s[3968]! } - public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3969]! } - public var AutoDownloadSettings_OffForAll: String { return self._s[3970]! } - public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3971]! } - public var Conversation_typing: String { return self._s[3973]! } - public var Undo_ScheduledMessagesCleared: String { return self._s[3974]! } - public var Paint_Masks: String { return self._s[3975]! } - public var Contacts_DeselectAll: String { return self._s[3976]! } + public var Exceptions_AddToExceptions: String { return self._s[3970]! } + public var AccessDenied_Settings: String { return self._s[3971]! } + public var Passport_Address_TypeUtilityBillUploadScan: String { return self._s[3972]! } + public var Month_ShortMay: String { return self._s[3973]! } + public var Compose_NewGroup: String { return self._s[3975]! } + public var Group_Setup_TypePrivate: String { return self._s[3977]! } + public var Login_PadPhoneHelpTitle: String { return self._s[3979]! } + public var Appearance_ThemeDayClassic: String { return self._s[3980]! } + public var Channel_AdminLog_MessagePreviousCaption: String { return self._s[3981]! } + public var AutoDownloadSettings_OffForAll: String { return self._s[3982]! } + public var Privacy_GroupsAndChannels_WhoCanAddMe: String { return self._s[3983]! } + public var Conversation_typing: String { return self._s[3985]! } + public var Undo_ScheduledMessagesCleared: String { return self._s[3986]! } + public var Paint_Masks: String { return self._s[3987]! } + public var Contacts_DeselectAll: String { return self._s[3988]! } public func Wallet_Updated_YesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3977]!, self._r[3977]!, [_0]) + return formatWithArgumentRanges(self._s[3989]!, self._r[3989]!, [_0]) } - public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3978]! } - public var Username_InvalidTaken: String { return self._s[3979]! } - public var Call_StatusNoAnswer: String { return self._s[3980]! } - public var TwoStepAuth_EmailAddSuccess: String { return self._s[3981]! } - public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3982]! } - public var Passport_Identity_Selfie: String { return self._s[3983]! } - public var Login_InfoLastNamePlaceholder: String { return self._s[3984]! } - public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3985]! } - public var Conversation_ClearSecretHistory: String { return self._s[3986]! } - public var PeopleNearby_Description: String { return self._s[3988]! } - public var NetworkUsageSettings_Title: String { return self._s[3989]! } - public var Your_cards_security_code_is_invalid: String { return self._s[3991]! } + public var CreatePoll_MultipleChoiceQuizAlert: String { return self._s[3990]! } + public var Username_InvalidTaken: String { return self._s[3991]! } + public var Call_StatusNoAnswer: String { return self._s[3992]! } + public var TwoStepAuth_EmailAddSuccess: String { return self._s[3993]! } + public var SettingsSearch_Synonyms_Privacy_BlockedUsers: String { return self._s[3994]! } + public var Passport_Identity_Selfie: String { return self._s[3995]! } + public var Login_InfoLastNamePlaceholder: String { return self._s[3996]! } + public var Privacy_SecretChatsLinkPreviewsHelp: String { return self._s[3997]! } + public var Conversation_ClearSecretHistory: String { return self._s[3998]! } + public var PeopleNearby_Description: String { return self._s[4000]! } + public var NetworkUsageSettings_Title: String { return self._s[4001]! } + public var Your_cards_security_code_is_invalid: String { return self._s[4003]! } public func Notification_LeftChannel(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3993]!, self._r[3993]!, [_0]) - } - public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[3994]!, self._r[3994]!, [_1, _2]) - } - public var SaveIncomingPhotosSettings_From: String { return self._s[3996]! } - public var VoiceOver_Navigation_Search: String { return self._s[3997]! } - public var Map_LiveLocationTitle: String { return self._s[3998]! } - public var Login_InfoAvatarAdd: String { return self._s[3999]! } - public var Passport_Identity_FilesView: String { return self._s[4000]! } - public var UserInfo_GenericPhoneLabel: String { return self._s[4001]! } - public var Privacy_Calls_NeverAllow: String { return self._s[4002]! } - public var VoiceOver_Chat_File: String { return self._s[4003]! } - public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4004]! } - public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { return formatWithArgumentRanges(self._s[4005]!, self._r[4005]!, [_0]) } - public var ContactInfo_PhoneNumberHidden: String { return self._s[4006]! } - public var TwoStepAuth_ConfirmationText: String { return self._s[4007]! } - public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4008]! } + public func Call_CallInProgressMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4006]!, self._r[4006]!, [_1, _2]) + } + public var SaveIncomingPhotosSettings_From: String { return self._s[4008]! } + public var VoiceOver_Navigation_Search: String { return self._s[4009]! } + public var Map_LiveLocationTitle: String { return self._s[4010]! } + public var Login_InfoAvatarAdd: String { return self._s[4011]! } + public var Passport_Identity_FilesView: String { return self._s[4012]! } + public var UserInfo_GenericPhoneLabel: String { return self._s[4013]! } + public var Privacy_Calls_NeverAllow: String { return self._s[4014]! } + public var VoiceOver_Chat_File: String { return self._s[4015]! } + public var Wallet_Settings_DeleteWalletInfo: String { return self._s[4016]! } + public func Contacts_AddPhoneNumber(_ _0: String) -> (String, [(Int, NSRange)]) { + return formatWithArgumentRanges(self._s[4017]!, self._r[4017]!, [_0]) + } + public var ContactInfo_PhoneNumberHidden: String { return self._s[4018]! } + public var TwoStepAuth_ConfirmationText: String { return self._s[4019]! } + public var ChatSettings_AutomaticVideoMessageDownload: String { return self._s[4020]! } public func PUSH_CHAT_MESSAGE_VIDEOS(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4009]!, self._r[4009]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4021]!, self._r[4021]!, [_1, _2, _3]) } - public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4010]! } - public var Wallet_Intro_CreateErrorText: String { return self._s[4011]! } - public var Tour_Title2: String { return self._s[4012]! } - public var Wallet_Sent_ViewWallet: String { return self._s[4013]! } - public var Conversation_FileOpenIn: String { return self._s[4014]! } - public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4015]! } - public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4016]! } - public var Wallpaper_Set: String { return self._s[4017]! } - public var Passport_Identity_Translations: String { return self._s[4019]! } + public var Channel_AdminLogFilter_AdminsAll: String { return self._s[4022]! } + public var Wallet_Intro_CreateErrorText: String { return self._s[4023]! } + public var Tour_Title2: String { return self._s[4024]! } + public var Wallet_Sent_ViewWallet: String { return self._s[4025]! } + public var Conversation_FileOpenIn: String { return self._s[4026]! } + public var Checkout_ErrorPrecheckoutFailed: String { return self._s[4027]! } + public var Wallet_Send_ErrorInvalidAddress: String { return self._s[4028]! } + public var Wallpaper_Set: String { return self._s[4029]! } + public var Passport_Identity_Translations: String { return self._s[4031]! } public func Channel_AdminLog_MessageChangedChannelAbout(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4020]!, self._r[4020]!, [_0]) + return formatWithArgumentRanges(self._s[4032]!, self._r[4032]!, [_0]) } - public var Channel_LeaveChannel: String { return self._s[4021]! } + public var Channel_LeaveChannel: String { return self._s[4033]! } public func PINNED_INVOICE(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4022]!, self._r[4022]!, [_1]) + return formatWithArgumentRanges(self._s[4034]!, self._r[4034]!, [_1]) } - public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4024]! } - public var PhotoEditor_HighlightsTint: String { return self._s[4025]! } - public var MessagePoll_LabelPoll: String { return self._s[4026]! } - public var Passport_Email_Delete: String { return self._s[4027]! } - public var Conversation_Mute: String { return self._s[4029]! } - public var Channel_AddBotAsAdmin: String { return self._s[4030]! } - public var Channel_AdminLog_CanSendMessages: String { return self._s[4032]! } - public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4033]! } - public var ChatSettings_IntentsSettings: String { return self._s[4035]! } - public var Channel_Management_LabelOwner: String { return self._s[4036]! } + public var SettingsSearch_Synonyms_Proxy_AddProxy: String { return self._s[4036]! } + public var PhotoEditor_HighlightsTint: String { return self._s[4037]! } + public var MessagePoll_LabelPoll: String { return self._s[4038]! } + public var Passport_Email_Delete: String { return self._s[4039]! } + public var Conversation_Mute: String { return self._s[4041]! } + public var Channel_AddBotAsAdmin: String { return self._s[4042]! } + public var Channel_AdminLog_CanSendMessages: String { return self._s[4044]! } + public var Wallet_Configuration_BlockchainNameChangedText: String { return self._s[4045]! } + public var ChatSettings_IntentsSettings: String { return self._s[4047]! } + public var Channel_Management_LabelOwner: String { return self._s[4048]! } public func Notification_PassportValuesSentMessage(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4037]!, self._r[4037]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4049]!, self._r[4049]!, [_1, _2]) } - public var Calls_CallTabDescription: String { return self._s[4038]! } - public var Passport_Identity_NativeNameHelp: String { return self._s[4039]! } - public var Common_No: String { return self._s[4040]! } - public var Weekday_Sunday: String { return self._s[4041]! } - public var Notification_Reply: String { return self._s[4042]! } - public var Conversation_ViewMessage: String { return self._s[4043]! } + public var Calls_CallTabDescription: String { return self._s[4050]! } + public var Passport_Identity_NativeNameHelp: String { return self._s[4051]! } + public var Common_No: String { return self._s[4052]! } + public var Weekday_Sunday: String { return self._s[4053]! } + public var Notification_Reply: String { return self._s[4054]! } + public var Conversation_ViewMessage: String { return self._s[4055]! } public func Checkout_SavePasswordTimeoutAndFaceId(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4044]!, self._r[4044]!, [_0]) + return formatWithArgumentRanges(self._s[4056]!, self._r[4056]!, [_0]) } public func Map_LiveLocationPrivateDescription(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4045]!, self._r[4045]!, [_0]) + return formatWithArgumentRanges(self._s[4057]!, self._r[4057]!, [_0]) } public func Wallet_Time_PreciseDate_m7(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4046]!, self._r[4046]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4058]!, self._r[4058]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4047]! } - public var Wallet_Send_Title: String { return self._s[4048]! } - public var Message_PinnedDocumentMessage: String { return self._s[4049]! } - public var Wallet_Info_RefreshErrorText: String { return self._s[4050]! } - public var DialogList_TabTitle: String { return self._s[4052]! } - public var ChatSettings_AutoPlayTitle: String { return self._s[4053]! } - public var Passport_FieldEmail: String { return self._s[4054]! } - public var Conversation_UnpinMessageAlert: String { return self._s[4055]! } - public var Passport_Address_TypeBankStatement: String { return self._s[4056]! } - public var Wallet_SecureStorageReset_Title: String { return self._s[4057]! } - public var Passport_Identity_ExpiryDate: String { return self._s[4058]! } - public var Privacy_Calls_P2P: String { return self._s[4059]! } + public var SettingsSearch_Synonyms_EditProfile_AddAccount: String { return self._s[4059]! } + public var Wallet_Send_Title: String { return self._s[4060]! } + public var Message_PinnedDocumentMessage: String { return self._s[4061]! } + public var Wallet_Info_RefreshErrorText: String { return self._s[4062]! } + public var DialogList_TabTitle: String { return self._s[4064]! } + public var ChatSettings_AutoPlayTitle: String { return self._s[4065]! } + public var Passport_FieldEmail: String { return self._s[4066]! } + public var Conversation_UnpinMessageAlert: String { return self._s[4067]! } + public var Passport_Address_TypeBankStatement: String { return self._s[4068]! } + public var Wallet_SecureStorageReset_Title: String { return self._s[4069]! } + public var Passport_Identity_ExpiryDate: String { return self._s[4070]! } + public var Privacy_Calls_P2P: String { return self._s[4071]! } public func CancelResetAccount_Success(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4061]!, self._r[4061]!, [_0]) + return formatWithArgumentRanges(self._s[4073]!, self._r[4073]!, [_0]) } - public var SocksProxySetup_UseForCallsHelp: String { return self._s[4062]! } + public var SocksProxySetup_UseForCallsHelp: String { return self._s[4074]! } public func PUSH_CHAT_ALBUM(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4063]!, self._r[4063]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4075]!, self._r[4075]!, [_1, _2]) } - public var Stickers_ClearRecent: String { return self._s[4064]! } - public var EnterPasscode_ChangeTitle: String { return self._s[4065]! } - public var TwoFactorSetup_Email_Title: String { return self._s[4066]! } - public var Passport_InfoText: String { return self._s[4067]! } - public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4068]! } + public var Stickers_ClearRecent: String { return self._s[4076]! } + public var EnterPasscode_ChangeTitle: String { return self._s[4077]! } + public var TwoFactorSetup_Email_Title: String { return self._s[4078]! } + public var Passport_InfoText: String { return self._s[4079]! } + public var Checkout_NewCard_SaveInfoEnableHelp: String { return self._s[4080]! } public func Login_InvalidPhoneEmailSubject(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4069]!, self._r[4069]!, [_0]) + return formatWithArgumentRanges(self._s[4081]!, self._r[4081]!, [_0]) } public func Time_PreciseDate_m3(_ _1: String, _ _2: String, _ _3: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4070]!, self._r[4070]!, [_1, _2, _3]) + return formatWithArgumentRanges(self._s[4082]!, self._r[4082]!, [_1, _2, _3]) } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4071]! } - public var ScheduledMessages_PollUnavailable: String { return self._s[4072]! } - public var VoiceOver_Navigation_Compose: String { return self._s[4073]! } - public var Passport_Identity_EditDriversLicense: String { return self._s[4074]! } - public var Conversation_TapAndHoldToRecord: String { return self._s[4076]! } - public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4077]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels: String { return self._s[4083]! } + public var ScheduledMessages_PollUnavailable: String { return self._s[4084]! } + public var VoiceOver_Navigation_Compose: String { return self._s[4085]! } + public var Passport_Identity_EditDriversLicense: String { return self._s[4086]! } + public var Conversation_TapAndHoldToRecord: String { return self._s[4088]! } + public var SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChats: String { return self._s[4089]! } public func Notification_CallTimeFormat(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4078]!, self._r[4078]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4090]!, self._r[4090]!, [_1, _2]) } - public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4080]! } - public var ChatSettings_OpenLinksIn: String { return self._s[4081]! } - public var Map_HomeAndWorkTitle: String { return self._s[4082]! } + public var Channel_EditAdmin_PermissionInviteViaLink: String { return self._s[4093]! } + public var ChatSettings_OpenLinksIn: String { return self._s[4094]! } + public var Map_HomeAndWorkTitle: String { return self._s[4095]! } public func Generic_OpenHiddenLinkAlert(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4084]!, self._r[4084]!, [_0]) + return formatWithArgumentRanges(self._s[4097]!, self._r[4097]!, [_0]) } - public var DialogList_Unread: String { return self._s[4085]! } + public var DialogList_Unread: String { return self._s[4098]! } public func PUSH_CHAT_MESSAGE_GIF(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4086]!, self._r[4086]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4099]!, self._r[4099]!, [_1, _2]) } - public var User_DeletedAccount: String { return self._s[4087]! } - public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4088]! } + public var User_DeletedAccount: String { return self._s[4100]! } + public var OwnershipTransfer_SetupTwoStepAuth: String { return self._s[4101]! } public func Watch_Time_ShortYesterdayAt(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4089]!, self._r[4089]!, [_0]) + return formatWithArgumentRanges(self._s[4102]!, self._r[4102]!, [_0]) } - public var UserInfo_NotificationsDefault: String { return self._s[4090]! } - public var SharedMedia_CategoryMedia: String { return self._s[4091]! } - public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4092]! } - public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4093]! } - public var Watch_ChatList_Compose: String { return self._s[4094]! } - public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4095]! } - public var AutoDownloadSettings_Delimeter: String { return self._s[4096]! } - public var Watch_Microphone_Access: String { return self._s[4097]! } - public var Group_Setup_HistoryHeader: String { return self._s[4098]! } - public var Map_SetThisLocation: String { return self._s[4099]! } - public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4100]! } - public var Activity_UploadingPhoto: String { return self._s[4101]! } - public var Conversation_Edit: String { return self._s[4103]! } - public var Group_ErrorSendRestrictedMedia: String { return self._s[4104]! } - public var Login_TermsOfServiceDecline: String { return self._s[4105]! } - public var Message_PinnedContactMessage: String { return self._s[4106]! } + public var UserInfo_NotificationsDefault: String { return self._s[4103]! } + public var SharedMedia_CategoryMedia: String { return self._s[4104]! } + public var SocksProxySetup_ProxyStatusUnavailable: String { return self._s[4105]! } + public var Channel_AdminLog_MessageRestrictedForever: String { return self._s[4106]! } + public var Watch_ChatList_Compose: String { return self._s[4107]! } + public var Notifications_MessageNotificationsExceptionsHelp: String { return self._s[4108]! } + public var AutoDownloadSettings_Delimeter: String { return self._s[4109]! } + public var Watch_Microphone_Access: String { return self._s[4110]! } + public var Group_Setup_HistoryHeader: String { return self._s[4111]! } + public var Map_SetThisLocation: String { return self._s[4112]! } + public var Appearance_ThemePreview_Chat_2_ReplyName: String { return self._s[4113]! } + public var Activity_UploadingPhoto: String { return self._s[4114]! } + public var Conversation_Edit: String { return self._s[4116]! } + public var Group_ErrorSendRestrictedMedia: String { return self._s[4117]! } + public var Login_TermsOfServiceDecline: String { return self._s[4118]! } + public var Message_PinnedContactMessage: String { return self._s[4119]! } public func Channel_AdminLog_MessageRestrictedNameUsername(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4107]!, self._r[4107]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4120]!, self._r[4120]!, [_1, _2]) } public func Login_PhoneBannedEmailBody(_ _1: String, _ _2: String, _ _3: String, _ _4: String, _ _5: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4108]!, self._r[4108]!, [_1, _2, _3, _4, _5]) + return formatWithArgumentRanges(self._s[4121]!, self._r[4121]!, [_1, _2, _3, _4, _5]) } - public var Appearance_LargeEmoji: String { return self._s[4109]! } - public var TwoStepAuth_AdditionalPassword: String { return self._s[4111]! } - public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4112]! } + public var Appearance_LargeEmoji: String { return self._s[4122]! } + public var TwoStepAuth_AdditionalPassword: String { return self._s[4124]! } + public var EditTheme_Edit_Preview_IncomingReplyText: String { return self._s[4125]! } public func PUSH_CHAT_DELETE_YOU(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4113]!, self._r[4113]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4126]!, self._r[4126]!, [_1, _2]) } - public var Passport_Phone_EnterOtherNumber: String { return self._s[4114]! } - public var Message_PinnedPhotoMessage: String { return self._s[4115]! } - public var Passport_FieldPhone: String { return self._s[4116]! } - public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4117]! } - public var ChatSettings_AutoPlayGifs: String { return self._s[4118]! } - public var InfoPlist_NSCameraUsageDescription: String { return self._s[4120]! } - public var Conversation_Call: String { return self._s[4121]! } - public var Common_TakePhoto: String { return self._s[4123]! } - public var Group_EditAdmin_RankTitle: String { return self._s[4124]! } - public var Wallet_Receive_CommentHeader: String { return self._s[4125]! } - public var Channel_NotificationLoading: String { return self._s[4126]! } + public var Passport_Phone_EnterOtherNumber: String { return self._s[4127]! } + public var Message_PinnedPhotoMessage: String { return self._s[4128]! } + public var Passport_FieldPhone: String { return self._s[4129]! } + public var TwoStepAuth_RecoveryEmailAddDescription: String { return self._s[4130]! } + public var ChatSettings_AutoPlayGifs: String { return self._s[4131]! } + public var InfoPlist_NSCameraUsageDescription: String { return self._s[4133]! } + public var Conversation_Call: String { return self._s[4134]! } + public var Common_TakePhoto: String { return self._s[4136]! } + public var Group_EditAdmin_RankTitle: String { return self._s[4137]! } + public var Wallet_Receive_CommentHeader: String { return self._s[4138]! } + public var Channel_NotificationLoading: String { return self._s[4139]! } public func Notification_Exceptions_Sound(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4127]!, self._r[4127]!, [_0]) + return formatWithArgumentRanges(self._s[4140]!, self._r[4140]!, [_0]) } public func ScheduledMessages_ScheduledDate(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4128]!, self._r[4128]!, [_0]) + return formatWithArgumentRanges(self._s[4141]!, self._r[4141]!, [_0]) } public func PUSH_CHANNEL_MESSAGE_VIDEO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4129]!, self._r[4129]!, [_1]) + return formatWithArgumentRanges(self._s[4142]!, self._r[4142]!, [_1]) } - public var Permissions_SiriTitle_v0: String { return self._s[4130]! } + public var Permissions_SiriTitle_v0: String { return self._s[4143]! } public func VoiceOver_Chat_VoiceMessageFrom(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4131]!, self._r[4131]!, [_0]) + return formatWithArgumentRanges(self._s[4144]!, self._r[4144]!, [_0]) } public func Login_ResetAccountProtected_Text(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4132]!, self._r[4132]!, [_0]) + return formatWithArgumentRanges(self._s[4145]!, self._r[4145]!, [_0]) } - public var Channel_MessagePhotoRemoved: String { return self._s[4133]! } - public var Wallet_Info_ReceiveGrams: String { return self._s[4134]! } - public var ClearCache_FreeSpace: String { return self._s[4135]! } - public var Common_edit: String { return self._s[4136]! } - public var PrivacySettings_AuthSessions: String { return self._s[4137]! } - public var Month_ShortJune: String { return self._s[4138]! } - public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4139]! } - public var Call_ReportSend: String { return self._s[4140]! } - public var Watch_LastSeen_JustNow: String { return self._s[4141]! } - public var Notifications_MessageNotifications: String { return self._s[4142]! } - public var WallpaperSearch_ColorGreen: String { return self._s[4143]! } - public var BroadcastListInfo_AddRecipient: String { return self._s[4145]! } - public var Group_Status: String { return self._s[4146]! } + public var Channel_MessagePhotoRemoved: String { return self._s[4146]! } + public var Wallet_Info_ReceiveGrams: String { return self._s[4147]! } + public var ClearCache_FreeSpace: String { return self._s[4148]! } + public var Common_edit: String { return self._s[4149]! } + public var PrivacySettings_AuthSessions: String { return self._s[4150]! } + public var Month_ShortJune: String { return self._s[4151]! } + public var PrivacyLastSeenSettings_AlwaysShareWith_Placeholder: String { return self._s[4152]! } + public var Call_ReportSend: String { return self._s[4153]! } + public var Watch_LastSeen_JustNow: String { return self._s[4154]! } + public var Notifications_MessageNotifications: String { return self._s[4155]! } + public var WallpaperSearch_ColorGreen: String { return self._s[4156]! } + public var BroadcastListInfo_AddRecipient: String { return self._s[4158]! } + public var Group_Status: String { return self._s[4159]! } public func AutoNightTheme_LocationHelp(_ _0: String, _ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4147]!, self._r[4147]!, [_0, _1]) + return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_0, _1]) } - public var TextFormat_AddLinkTitle: String { return self._s[4148]! } - public var ShareMenu_ShareTo: String { return self._s[4149]! } - public var Conversation_Moderate_Ban: String { return self._s[4150]! } + public var TextFormat_AddLinkTitle: String { return self._s[4161]! } + public var ShareMenu_ShareTo: String { return self._s[4162]! } + public var Conversation_Moderate_Ban: String { return self._s[4163]! } public func Conversation_DeleteMessagesFor(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4151]!, self._r[4151]!, [_0]) + return formatWithArgumentRanges(self._s[4164]!, self._r[4164]!, [_0]) } - public var SharedMedia_ViewInChat: String { return self._s[4152]! } - public var Map_LiveLocationFor8Hours: String { return self._s[4153]! } + public var SharedMedia_ViewInChat: String { return self._s[4165]! } + public var Map_LiveLocationFor8Hours: String { return self._s[4166]! } public func PUSH_PINNED_PHOTO(_ _1: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4154]!, self._r[4154]!, [_1]) + return formatWithArgumentRanges(self._s[4167]!, self._r[4167]!, [_1]) } public func PUSH_PINNED_POLL(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4155]!, self._r[4155]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4168]!, self._r[4168]!, [_1, _2]) } public func Map_AccurateTo(_ _0: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4157]!, self._r[4157]!, [_0]) + return formatWithArgumentRanges(self._s[4170]!, self._r[4170]!, [_0]) } - public var Map_OpenInHereMaps: String { return self._s[4158]! } - public var Appearance_ReduceMotion: String { return self._s[4159]! } + public var Map_OpenInHereMaps: String { return self._s[4171]! } + public var Appearance_ReduceMotion: String { return self._s[4172]! } public func PUSH_MESSAGE_TEXT(_ _1: String, _ _2: String) -> (String, [(Int, NSRange)]) { - return formatWithArgumentRanges(self._s[4160]!, self._r[4160]!, [_1, _2]) + return formatWithArgumentRanges(self._s[4173]!, self._r[4173]!, [_1, _2]) } - public var Channel_Setup_TypePublicHelp: String { return self._s[4161]! } - public var Passport_Identity_EditInternalPassport: String { return self._s[4162]! } - public var PhotoEditor_Skip: String { return self._s[4163]! } - public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { + public var Channel_Setup_TypePublicHelp: String { return self._s[4174]! } + public var Passport_Identity_EditInternalPassport: String { return self._s[4175]! } + public var PhotoEditor_Skip: String { return self._s[4176]! } + public func Notification_GameScoreSimple(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue) } - public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortWeeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedStickers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedPhotos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) - } - public func QuickSend_Photos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, stringValue) - } - public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Map_ETAMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteFor_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeleteConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortHours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_Generic(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) - } public func PUSH_CHAT_MESSAGE_PHOTOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, _2, _1, _3) + return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, _2, _1, _3) } public func Wallpaper_DeleteConfirmation(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_InviteContacts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) - } - public func GroupInfo_ParticipantCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) - } - public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PollResults_ShowMore(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func MessageTimer_Months(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func InviteText_ContactsCountText(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_ShareVideo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_SelectedMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Years(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Passport_Scans(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, _0, _1) - } - public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessagePoll_QuizCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func SharedMedia_Video(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveYear(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_InactiveWeek(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) - } - public func UserCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_ShortSeconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Weeks(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Theme_UsersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendItem(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_Exceptions(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_ShortDays(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedFiles(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Contacts_ImportersCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideoMessages(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_SelectedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Media_SharePhoto(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedGifs(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedVideos(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_AddStickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ChatList_DeletedChats(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) - } - public func AttachmentMenu_SendGif(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[2 * 6 + Int(form.rawValue)]!, stringValue) } public func Media_ShareItem(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[3 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + public func Media_ShareVideo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[4 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessageTimer_Seconds(_ value: Int32) -> String { + public func GroupInfo_ParticipantCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[5 * 6 + Int(form.rawValue)]!, stringValue) } - public func MuteExpires_Days(_ value: Int32) -> String { + public func LiveLocationUpdated_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[6 * 6 + Int(form.rawValue)]!, stringValue) } - public func OldChannels_InactiveMonth(_ value: Int32) -> String { + public func MuteExpires_Hours(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[7 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_AddMaskCount(_ value: Int32) -> String { + public func LastSeen_MinutesAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[8 * 6 + Int(form.rawValue)]!, stringValue) } - public func MessagePoll_VotedCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) - } - public func SharedMedia_File(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Watch_UserInfo_Mute(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[9 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Notification_GameScoreExtended(_ value: Int32) -> String { + public func Notifications_Exceptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[10 * 6 + Int(form.rawValue)]!, stringValue) } - public func StickerPack_StickerCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) - } - public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MuteExpires_Minutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) - } - public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusOnline(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Call_Seconds(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, _1, _2) - } - public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) - } - public func Conversation_StatusMembers(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ForwardedLocations(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) - } - public func OldChannels_GroupFormat(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) - } - public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, _2, _1, _3) - } - public func ForwardedAudios(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) - } - public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Days(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, stringValue) - } - public func MessageTimer_Hours(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[11 * 6 + Int(form.rawValue)]!, _1, _2) } public func LastSeen_HoursAgo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[12 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[13 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAHours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[14 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPhotos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[15 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[16 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PUSH_CHANNEL_MESSAGE_VIDEOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[17 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func SharedMedia_File(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[18 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGE_ROUNDS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[19 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func Contacts_InviteContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[20 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[21 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortWeeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[22 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[23 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Contacts_ImportersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[24 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Chat_DeleteMessagesConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[25 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[26 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[27 * 6 + Int(form.rawValue)]!, stringValue) + } + public func InviteText_ContactsCountText(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[28 * 6 + Int(form.rawValue)]!, stringValue) } public func MessageTimer_ShortSeconds(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[29 * 6 + Int(form.rawValue)]!, stringValue) } - public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[30 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, _1, _2) + public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[31 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Forward_ConfirmMultipleFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[32 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Passport_Scans(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[33 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[34 * 6 + Int(form.rawValue)]!, stringValue) } public func SharedMedia_Photo(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + return String(format: self._ps[35 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[36 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[37 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func PrivacyLastSeenSettings_AddUsers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[38 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_ShortMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[39 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Weeks(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[40 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactEmailCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[41 * 6 + Int(form.rawValue)]!, stringValue) + } + public func UserCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[42 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendItem(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[43 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_DeletedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[44 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Invitation_Members(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[45 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollOptionCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[46 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[47 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[48 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedStickers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[49 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_SelectedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[50 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveMaskCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[51 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_StickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[52 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_PHOTOS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[53 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func MessageTimer_Hours(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[54 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_RemoveStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[55 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[56 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func ForwardedContacts(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[57 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_UserInfo_Mute(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[58 * 6 + Int(form.rawValue)]!, stringValue) + } + public func AttachmentMenu_SendGif(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[59 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ChatList_SelectedChats(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[60 * 6 + Int(form.rawValue)]!, stringValue) + } + public func GroupInfo_ShowMoreMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[61 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusOnline(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[62 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Generic(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[63 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[64 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_Video(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[65 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[66 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func ForwardedFiles(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[67 * 6 + Int(form.rawValue)]!, stringValue) + } + public func SharedMedia_DeleteItemsConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[68 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_Seconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[69 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Call_ShortSeconds(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[70 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_ContactPhoneNumberCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[71 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MuteExpires_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[72 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAuthorsOthers(_ selector: Int32, _ _0: String, _ _1: String) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[73 * 6 + Int(form.rawValue)]!, _0, _1) + } + public func MessageTimer_ShortDays(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[74 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Watch_LastSeen_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[75 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusMembers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[76 * 6 + Int(form.rawValue)]!, stringValue) } public func OldChannels_Leave(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[77 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Days(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[78 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[79 * 6 + Int(form.rawValue)]!, stringValue) + } + public func StickerPack_AddStickerCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[80 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveYear(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[81 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedLocations(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[82 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessageTimer_Years(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[83 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PollResults_ShowMore(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[84 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Media_SharePhoto(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[85 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Conversation_StatusSubscribers(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[86 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_VotedCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[87 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_GroupFormat(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[88 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notifications_ExceptionMuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[89 * 6 + Int(form.rawValue)]!, stringValue) + } + public func OldChannels_InactiveWeek(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[90 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedMessages(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[91 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Theme_UsersCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[92 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[93 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHANNEL_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[94 * 6 + Int(form.rawValue)]!, _1, _2) + } + public func QuickSend_Photos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[95 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Map_ETAMinutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[96 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Wallet_Updated_HoursAgo(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[97 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreExtended(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[98 * 6 + Int(form.rawValue)]!, stringValue) + } + public func DialogList_LiveLocationChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[99 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedVideos(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[100 * 6 + Int(form.rawValue)]!, stringValue) + } + public func VoiceOver_Chat_PollVotes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[101 * 6 + Int(form.rawValue)]!, stringValue) + } + public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[102 * 6 + Int(form.rawValue)]!, _2, _1, _3) + } + public func ChatList_DeleteConfirmation(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[103 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedPolls(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[104 * 6 + Int(form.rawValue)]!, stringValue) + } + public func Notification_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[105 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ForwardedAudios(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[106 * 6 + Int(form.rawValue)]!, stringValue) + } + public func ServiceMessage_GameScoreSelfSimple(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[107 * 6 + Int(form.rawValue)]!, stringValue) + } + public func LiveLocation_MenuChatsCount(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[108 * 6 + Int(form.rawValue)]!, stringValue) + } + public func MessagePoll_QuizCount(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[109 * 6 + Int(form.rawValue)]!, stringValue) } - public func AttachmentMenu_SendVideo(_ value: Int32) -> String { + public func SharedMedia_Link(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[110 * 6 + Int(form.rawValue)]!, stringValue) @@ -5235,30 +5245,30 @@ public final class PresentationStrings: Equatable { let form = getPluralizationForm(self.lc, selector) return String(format: self._ps[111 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func MessageTimer_ShortMinutes(_ value: Int32) -> String { - let form = getPluralizationForm(self.lc, value) - let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) - return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, stringValue) + public func PUSH_MESSAGE_ROUNDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + let form = getPluralizationForm(self.lc, selector) + return String(format: self._ps[112 * 6 + Int(form.rawValue)]!, _1, _2) } - public func Conversation_StatusSubscribers(_ value: Int32) -> String { + public func MuteFor_Days(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[113 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedPolls(_ value: Int32) -> String { + public func ForwardedVideoMessages(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[114 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_CHAT_MESSAGES(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, _2, _1, _3) + public func OldChannels_InactiveMonth(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[115 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGES(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { + public func PUSH_CHAT_MESSAGE_VIDEOS(_ selector: Int32, _ _2: String, _ _1: String, _ _3: Int32) -> String { let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _1, _2) + return String(format: self._ps[116 * 6 + Int(form.rawValue)]!, _2, _1, _3) } - public func Map_ETAHours(_ value: Int32) -> String { + public func MessageTimer_Months(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[117 * 6 + Int(form.rawValue)]!, stringValue) @@ -5268,40 +5278,46 @@ public final class PresentationStrings: Equatable { let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[118 * 6 + Int(form.rawValue)]!, stringValue) } - public func Notification_GameScoreSimple(_ value: Int32) -> String { + public func CreatePoll_AddMoreOptions(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[119 * 6 + Int(form.rawValue)]!, stringValue) } - public func ForwardedContacts(_ value: Int32) -> String { + public func ForwardedGifs(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[120 * 6 + Int(form.rawValue)]!, stringValue) } - public func ServiceMessage_GameScoreSimple(_ value: Int32) -> String { + public func MessageTimer_Minutes(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[121 * 6 + Int(form.rawValue)]!, stringValue) } - public func Conversation_LiveLocationMembersCount(_ value: Int32) -> String { + public func PasscodeSettings_FailedAttempts(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[122 * 6 + Int(form.rawValue)]!, stringValue) } - public func SharedMedia_Link(_ value: Int32) -> String { + public func MessageTimer_ShortHours(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[123 * 6 + Int(form.rawValue)]!, stringValue) } - public func PUSH_MESSAGE_FWDS(_ selector: Int32, _ _1: String, _ _2: Int32) -> String { - let form = getPluralizationForm(self.lc, selector) - return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, _1, _2) + public func PeopleNearby_ShowMorePeople(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[124 * 6 + Int(form.rawValue)]!, stringValue) } - public func Invitation_Members(_ value: Int32) -> String { + public func AttachmentMenu_SendPhoto(_ value: Int32) -> String { let form = getPluralizationForm(self.lc, value) let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) return String(format: self._ps[125 * 6 + Int(form.rawValue)]!, stringValue) } + public func MuteExpires_Minutes(_ value: Int32) -> String { + let form = getPluralizationForm(self.lc, value) + let stringValue = presentationStringsFormattedNumber(value, self.groupingSeparator) + return String(format: self._ps[126 * 6 + Int(form.rawValue)]!, stringValue) + } public init(primaryComponent: PresentationStringsComponent, secondaryComponent: PresentationStringsComponent?, groupingSeparator: String) { self.primaryComponent = primaryComponent diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index a1b0744fad..ff03ac0902 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -48,6 +48,8 @@ public enum PresentationResourceKey: Int32 { case itemListVerifiedPeerIcon case itemListCloudFetchIcon case itemListCloseIconImage + case itemListMakeVisibleIcon + case itemListMakeInvisibleIcon case itemListCornersTop case itemListCornersBottom case itemListCornersBoth diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift index 53b0efb48f..8a3e6fc808 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift @@ -152,6 +152,18 @@ public struct PresentationResourcesItemList { }) } + public static func makeVisibleIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.itemListMakeVisibleIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeVisibleIcon"), color: theme.list.itemAccentColor) + }) + } + + public static func makeInvisibleIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.itemListMakeInvisibleIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Contact List/MakeInvisibleIcon"), color: theme.list.itemDestructiveColor) + }) + } + public static func cornersImage(_ theme: PresentationTheme, top: Bool, bottom: Bool) -> UIImage? { if !top && !bottom { return nil diff --git a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift index b7bdd08a48..31893c0e27 100644 --- a/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PresenceStrings.swift @@ -109,12 +109,13 @@ public func stringForMonth(strings: PresentationStrings, month: Int32, ofYear ye public enum RelativeTimestampFormatDay { case today case yesterday + case tomorrow } public func stringForUserPresence(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { - case .today: + case .today, .tomorrow: dayString = strings.LastSeen_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 case .yesterday: dayString = strings.LastSeen_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 @@ -125,10 +126,13 @@ public func stringForUserPresence(strings: PresentationStrings, day: RelativeTim private func humanReadableStringForTimestamp(strings: PresentationStrings, day: RelativeTimestampFormatDay, dateTimeFormat: PresentationDateTimeFormat, hours: Int32, minutes: Int32) -> String { let dayString: String switch day { - case .today: - dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 - case .yesterday: - dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .today: + dayString = strings.Time_TodayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .yesterday: + dayString = strings.Time_YesterdayAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + case .tomorrow: + dayString = strings.Time_TomorrowAt(stringForShortTimestamp(hours: hours, minutes: minutes, dateTimeFormat: dateTimeFormat)).0 + } return dayString } @@ -148,12 +152,14 @@ public func humanReadableStringForTimestamp(strings: PresentationStrings, dateTi } let dayDifference = timeinfo.tm_yday - timeinfoNow.tm_yday - if dayDifference == 0 || dayDifference == -1 { + if dayDifference == 0 || dayDifference == -1 || dayDifference == 1 { let day: RelativeTimestampFormatDay if dayDifference == 0 { day = .today - } else { + } else if dayDifference == -1 { day = .yesterday + } else { + day = .tomorrow } return humanReadableStringForTimestamp(strings: strings, day: day, dateTimeFormat: dateTimeFormat, hours: timeinfo.tm_hour, minutes: timeinfo.tm_min) } else { diff --git a/submodules/TelegramUI/Images.xcassets/Chart/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/Contents.json new file mode 100644 index 0000000000..38f0c81fc2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "provides-namespace" : true + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json new file mode 100644 index 0000000000..78b05b5e2a --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow_left.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf new file mode 100644 index 0000000000..7b20434672 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chart/arrow_left.imageset/arrow_left.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json new file mode 100644 index 0000000000..147027fa6d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "arrow_right.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf new file mode 100644 index 0000000000..baf05c2435 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chart/arrow_right.imageset/arrow_right.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/Contents.json new file mode 100644 index 0000000000..65481db2a7 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "selection_frame_dark.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "stretch", + "width" : 1 + }, + "cap-insets" : { + "right" : 11, + "left" : 11 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/selection_frame_dark.pdf b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/selection_frame_dark.pdf new file mode 100644 index 0000000000..ae27128091 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_dark.imageset/selection_frame_dark.pdf @@ -0,0 +1,61 @@ +%PDF-1.4 +% +1 0 obj +<> +endobj +2 0 obj +<> stream +xMN1 9H .,8bD{ 'vBZ$&(zv9#@[OG@$mޞy er:kptiک >) ԩS J) zKHf7.< U l5(ez;n[fscwN5&oW\~ɷtm`v{ *CK=N' |T[Rb35LdvuMU D-=1XׁTa'ۀzqncM="X+& -yKS +endstream +endobj +3 0 obj +<> +endobj +4 0 obj +<> +endobj +5 0 obj +<>>> +/MediaBox [0 0 114 42] +/Contents 2 0 R +/Parent 4 0 R>> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000089 00000 n +0000000482 00000 n +0000000529 00000 n +0000000584 00000 n +0000000765 00000 n +0000000802 00000 n +trailer +<> +startxref +880 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json new file mode 100644 index 0000000000..8cc38ca79c --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "selection_frame_light.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "stretch", + "width" : 1 + }, + "cap-insets" : { + "right" : 11, + "left" : 11 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf new file mode 100644 index 0000000000..c426c5d695 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chart/selection_frame_light.imageset/selection_frame_light.pdf @@ -0,0 +1,62 @@ +%PDF-1.4 +% +1 0 obj +<> +endobj +2 0 obj +<> stream +xN0 ~ +'yp*NY6$5uH&M3!U;ur:(`PĒ8 weT-)s+w0ofn2zrkM~q=[  V{ ]]b5^8U '䖄&?ȽƋ1NdBuQZmP2{Q DʠՆ8-,l lx} E>nr_1io|BV +endstream +endobj +3 0 obj +<> +endobj +4 0 obj +<> +endobj +5 0 obj +<>>> +/MediaBox [0 0 114 42] +/Contents 2 0 R +/Parent 4 0 R>> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +xref +0 8 +0000000000 65535 f +0000000015 00000 n +0000000089 00000 n +0000000482 00000 n +0000000529 00000 n +0000000584 00000 n +0000000765 00000 n +0000000802 00000 n +trailer +<> +startxref +880 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json new file mode 100644 index 0000000000..38f0c81fc2 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "provides-namespace" : true + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json new file mode 100644 index 0000000000..9afc9c4e5d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_calls.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf new file mode 100644 index 0000000000..f42e5fe81b Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconCalls.imageset/ic_calls.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/Contents.json new file mode 100644 index 0000000000..3637003f27 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_messages.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/ic_messages.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/ic_messages.pdf new file mode 100644 index 0000000000..64aba1907d Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconChats.imageset/ic_messages.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json new file mode 100644 index 0000000000..006f82fb71 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_contacts.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf new file mode 100644 index 0000000000..41f48e4e2d Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconContacts.imageset/ic_contacts.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/Contents.json new file mode 100644 index 0000000000..261d9ff3a9 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_settings.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/ic_settings.pdf b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/ic_settings.pdf new file mode 100644 index 0000000000..0f3b0dc083 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat List/Tabs/Holiday/IconSettings.imageset/ic_settings.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json new file mode 100644 index 0000000000..7abcd976aa --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_stopshowme.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf new file mode 100644 index 0000000000..9cc4c3d65a Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Contact List/MakeInvisibleIcon.imageset/ic_stopshowme.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json new file mode 100644 index 0000000000..97cc9be019 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_showme.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf new file mode 100644 index 0000000000..0c5a6e2133 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Contact List/MakeVisibleIcon.imageset/ic_showme.pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/Contents.json new file mode 100644 index 0000000000..d2ce704e18 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "soundoff (2).pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/soundoff (2).pdf b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/soundoff (2).pdf new file mode 100644 index 0000000000..8051a2a4e0 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOff.imageset/soundoff (2).pdf differ diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json new file mode 100644 index 0000000000..1d93d33a26 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "soundon (2).pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf new file mode 100644 index 0000000000..20236a226b Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Media Gallery/SoundOn.imageset/soundon (2).pdf differ diff --git a/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift b/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift index be5f243176..7e6470fbf2 100644 --- a/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatBotInfoItem.swift @@ -117,7 +117,7 @@ final class ChatBotInfoItemNode: ListViewItemNode { break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .tooltip: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip: return .waitForSingleTap } } diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index b07dae10d7..d62259a257 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -1358,6 +1358,33 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G ])]) strongSelf.chatDisplayNode.dismissInput() strongSelf.present(actionSheet, in: .window(.root)) + case let .bankCard(number): + guard let message = message else { + return + } + let _ = (getBankCardInfo(account: strongSelf.context.account, cardNumber: number) + |> deliverOnMainQueue).start(next: { [weak self] info in + if let strongSelf = self, let info = info { + let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) + var items: [ActionSheetItem] = [] + items.append(ActionSheetTextItem(title: info.title)) + if let url = info.url, let actionTitle = info.actionTitle { + items.append(ActionSheetButtonItem(title: actionTitle, color: .accent, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + if let strongSelf = self { + strongSelf.controllerInteraction?.openUrl(url, false, false, message) + } + })) + } + actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ + ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in + actionSheet?.dismissAnimated() + }) + ])]) + strongSelf.present(actionSheet, in: .window(.root)) + } + }) + strongSelf.chatDisplayNode.dismissInput() } } }, openCheckoutOrReceipt: { [weak self] messageId in diff --git a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift index fdae414c0a..e9b15f43af 100644 --- a/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/TelegramUI/ChatControllerInteraction.swift @@ -42,6 +42,7 @@ public enum ChatControllerInteractionLongTapAction { case command(String) case hashtag(String) case timecode(Double, String) + case bankCard(String) } struct ChatInterfacePollActionState: Equatable { @@ -119,6 +120,7 @@ public final class ChatControllerInteraction { var stickerSettings: ChatInterfaceStickerSettings var searchTextHighightState: (String, [MessageIndex])? var seenOneTimeAnimatedMedia = Set() + var seenDicePointsValue = [MessageId: Int]() init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) { self.openMessage = openMessage diff --git a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift index ab032691e6..6fb53ab372 100644 --- a/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatHistoryListNode.swift @@ -13,6 +13,7 @@ import AccountContext import TemporaryCachedPeerDataManager import ChatListSearchItemNode import Emoji +import AppBundle private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer { private let selectionGestureActivationThreshold: CGFloat = 5.0 @@ -308,7 +309,7 @@ private final class ChatHistoryTransactionOpaqueState { } } -private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: StickerPackItem], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData { +private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData { var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel var contactsPeerIds: Set = Set() if case let .peer(peerId) = chatLocation { @@ -605,19 +606,31 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { |> distinctUntilChanged let animatedEmojiStickers = loadedStickerPack(postbox: context.account.postbox, network: context.account.network, reference: .animatedEmoji, forceActualized: false) - |> map { result -> [String: StickerPackItem] in + |> map { result -> [String: [StickerPackItem]] in switch result { case let .result(_, items, _): - var animatedEmojiStickers: [String: StickerPackItem] = [:] + var animatedEmojiStickers: [String: [StickerPackItem]] = [:] for case let item as StickerPackItem in items { if let emoji = item.getStringRepresentationsOfIndexKeys().first { - animatedEmojiStickers[emoji.basicEmoji.0] = item + animatedEmojiStickers[emoji.basicEmoji.0] = [item] let strippedEmoji = emoji.basicEmoji.0.strippedEmoji if animatedEmojiStickers[strippedEmoji] == nil { - animatedEmojiStickers[strippedEmoji] = item + animatedEmojiStickers[strippedEmoji] = [item] } } } + + if let path = getAppBundle().path(forResource: "Dice_1", ofType: "tgs") { + var dices: [StickerPackItem] = [] + for i in 1...6 { + let path = path.replacingOccurrences(of: "_1", with: "_\(i)") + let id = arc4random64() + let resource = LocalFileReferenceMediaResource(localFilePath: path, randomId: id) + dices.append(StickerPackItem(index: ItemCollectionItemIndex(index: Int32(i), id: Int64(i)), file: TelegramMediaFile(fileId: MediaId(namespace: 10, id: Int64(i)), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgsticker", size: nil, attributes: []), indexKeys: [])) + } + animatedEmojiStickers["🎲".strippedEmoji] = dices + } + return animatedEmojiStickers default: return [:] diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift index 0cbef84d24..0098397abf 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift @@ -255,9 +255,24 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { let (emoji, fitz) = item.message.text.basicEmoji if self.telegramFile == nil { - var emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.file - if emojiFile == nil { - emojiFile = item.associatedData.animatedEmojiStickers[emoji.strippedEmoji]?.file + var emojiFile: TelegramMediaFile? + + if emoji == "🎲" { + var pointsValue: Int + if let value = item.controllerInteraction.seenDicePointsValue[item.message.id] { + pointsValue = value + } else { + pointsValue = Int(arc4random_uniform(6)) + item.controllerInteraction.seenDicePointsValue[item.message.id] = pointsValue + } + if let diceEmojis = item.associatedData.animatedEmojiStickers[emoji] { + emojiFile = diceEmojis[pointsValue].file + } + } else { + emojiFile = item.associatedData.animatedEmojiStickers[emoji]?.first?.file + if emojiFile == nil { + emojiFile = item.associatedData.animatedEmojiStickers[emoji.strippedEmoji]?.first?.file + } } if self.emojiFile?.id != emojiFile?.id { @@ -293,8 +308,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } self.animationNode.visibility = isPlaying && !alreadySeen + if self.didSetUpAnimationNode && alreadySeen { - self.animationNode.seekToStart() + if let emojiFile = self.emojiFile, emojiFile.resource is LocalFileReferenceMediaResource { + } else { + self.animationNode.seekTo(.start) + } } if self.isPlaying && !self.didSetUpAnimationNode { @@ -313,7 +332,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else if let emojiFile = self.emojiFile { isEmoji = true file = emojiFile - playbackMode = .once + if alreadySeen && emojiFile.resource is LocalFileReferenceMediaResource { + playbackMode = .still(.end) + } else { + playbackMode = .once + } let (_, fitz) = item.message.text.basicEmoji if let fitz = fitz { fitzModifier = EmojiFitzModifier(emoji: fitz) @@ -323,7 +346,13 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let file = file { let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedSize = isEmoji ? dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)) : dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) - self.animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: file.resource, fitzModifier: fitzModifier), width: Int(fittedSize.width), height: Int(fittedSize.height), playbackMode: playbackMode, mode: .cached) + let mode: AnimatedStickerMode + if file.resource is LocalFileReferenceMediaResource { + mode = .direct + } else { + mode = .cached + } + self.animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: file.resource, fitzModifier: fitzModifier), width: Int(fittedSize.width), height: Int(fittedSize.height), playbackMode: playbackMode, mode: mode) } } } @@ -870,34 +899,59 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if self.telegramFile != nil { let _ = item.controllerInteraction.openMessage(item.message, .default) } else if let _ = self.emojiFile { - var startTime: Signal - if self.animationNode.playIfNeeded() { - startTime = .single(0.0) + let (emoji, fitz) = item.message.text.basicEmoji + if emoji == "🎲" { + if !self.animationNode.isPlaying { + var pointsValue = Int(arc4random_uniform(6)) + item.controllerInteraction.seenDicePointsValue[item.message.id] = pointsValue + item.controllerInteraction.seenOneTimeAnimatedMedia.remove(item.message.id) + + var emojiFile: TelegramMediaFile? + if let diceEmojis = item.associatedData.animatedEmojiStickers[emoji] { + emojiFile = diceEmojis[pointsValue].file + } + + self.emojiFile = emojiFile + if let emojiFile = emojiFile { + let dimensions = emojiFile.dimensions ?? PixelDimensions(width: 512, height: 512) + self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: item.context.account.postbox, file: emojiFile, small: false, size: dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)), fitzModifier: nil, thumbnail: false)) + self.disposable.set(freeMediaFileInteractiveFetched(account: item.context.account, fileReference: .standalone(media: emojiFile)).start()) + } + self.isPlaying = false + self.didSetUpAnimationNode = false + self.updateVisibility() + self.animationNode.playIfNeeded() + } } else { - startTime = self.animationNode.status + var startTime: Signal + if self.animationNode.playIfNeeded() { + startTime = .single(0.0) + } else { + startTime = self.animationNode.status |> map { $0.timestamp } |> take(1) |> deliverOnMainQueue - } - - if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { - let _ = startTime.start(next: { [weak self] time in - guard let strongSelf = self else { - return - } - - let heartbeatHaptic: ChatMessageHeartbeatHaptic - if let current = strongSelf.heartbeatHaptic { - heartbeatHaptic = current - } else { - heartbeatHaptic = ChatMessageHeartbeatHaptic() - heartbeatHaptic.enabled = true - strongSelf.heartbeatHaptic = heartbeatHaptic - } - if !heartbeatHaptic.active { - heartbeatHaptic.start(time: time) - } - }) + } + + if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { + let _ = startTime.start(next: { [weak self] time in + guard let strongSelf = self else { + return + } + + let heartbeatHaptic: ChatMessageHeartbeatHaptic + if let current = strongSelf.heartbeatHaptic { + heartbeatHaptic = current + } else { + heartbeatHaptic = ChatMessageHeartbeatHaptic() + heartbeatHaptic.enabled = true + strongSelf.heartbeatHaptic = heartbeatHaptic + } + if !heartbeatHaptic.active { + heartbeatHaptic.start(time: time) + } + }) + } } } return true diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift index 0e565d40fb..bfb409db6b 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAttachedContentNode.swift @@ -1019,7 +1019,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { TelegramTextAttributes.PeerMention, TelegramTextAttributes.PeerTextMention, TelegramTextAttributes.BotCommand, - TelegramTextAttributes.Hashtag + TelegramTextAttributes.Hashtag, + TelegramTextAttributes.BankCard ] for name in possibleNames { if let _ = attributes[NSAttributedString.Key(rawValue: name)] { diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift index 4c10c8609a..0e2b2d8b2f 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleContentNode.swift @@ -80,6 +80,7 @@ enum ChatMessageBubbleContentTapAction { case openMessage case timecode(Double, String) case tooltip(String, ASDisplayNode?, CGRect?) + case bankCard(String) case ignore } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift index a507081fd5..93f968a020 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageBubbleItemNode.swift @@ -355,7 +355,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode break case .ignore: return .fail - case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .tooltip: + case .url, .peerMention, .textMention, .botCommand, .hashtag, .instantPage, .wallpaper, .theme, .call, .openMessage, .timecode, .bankCard, .tooltip: return .waitForSingleTap } } @@ -2381,6 +2381,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode item.controllerInteraction.seekToTimecode(mediaMessage, timecode, forceOpen) } break loop + case let .bankCard(number): + foundTapAction = true + if let item = self.item { + item.controllerInteraction.longTap(.bankCard(number), item.message) + } case let .tooltip(text, node, rect): foundTapAction = true if let item = self.item { @@ -2447,6 +2452,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode item.controllerInteraction.longTap(.timecode(timecode, text), mediaMessage) } break loop + case let .bankCard(number): + foundTapAction = true + item.controllerInteraction.longTap(.bankCard(number), message) case .tooltip: break } diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift b/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift index 26af9b2098..fe50b15654 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageItem.swift @@ -226,10 +226,10 @@ public final class ChatMessageItemAssociatedData: Equatable { let isRecentActions: Bool let isScheduledMessages: Bool let contactsPeerIds: Set - let animatedEmojiStickers: [String: StickerPackItem] + let animatedEmojiStickers: [String: [StickerPackItem]] let forcedResourceStatus: FileMediaResourceStatus? - init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set = Set(), animatedEmojiStickers: [String: StickerPackItem] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) { + init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set = Set(), animatedEmojiStickers: [String: [StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) { self.automaticDownloadPeerType = automaticDownloadPeerType self.automaticDownloadNetworkType = automaticDownloadNetworkType self.isRecentActions = isRecentActions diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift index 31b1d33df8..5df3808ac2 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -428,6 +428,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { return .hashtag(hashtag.peerName, hashtag.hashtag) } else if let timecode = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Timecode)] as? TelegramTimecode { return .timecode(timecode.time, timecode.text) + } else if let bankCard = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String { + return .bankCard(bankCard) } else { return .none } @@ -451,7 +453,8 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { TelegramTextAttributes.PeerTextMention, TelegramTextAttributes.BotCommand, TelegramTextAttributes.Hashtag, - TelegramTextAttributes.Timecode + TelegramTextAttributes.Timecode, + TelegramTextAttributes.BankCard ] for name in possibleNames { if let _ = attributes[NSAttributedString.Key(rawValue: name)] { diff --git a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift index cf5344ad57..b4de87c21a 100644 --- a/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatRecentActionsControllerNode.swift @@ -392,6 +392,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }) ])]) strongSelf.presentController(actionSheet, nil) + case .bankCard: + break } } }, openCheckoutOrReceipt: { _ in diff --git a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift index 4b77d486aa..e69a824772 100644 --- a/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatScheduleTimeControllerNode.swift @@ -352,7 +352,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - buttonHeight - insets.bottom - 10.0 - buttonOffset, width: contentFrame.width, height: buttonHeight)) let onlineSize = self.onlineButton.measure(CGSize(width: width, height: titleHeight)) - let onlineFrame = CGRect(origin: CGPoint(x: ceil((layout.size.width - onlineSize.width) / 2.0), y: contentHeight - 45.0 - insets.bottom), size: onlineSize) + let onlineFrame = CGRect(origin: CGPoint(x: ceil((contentFrame.width - onlineSize.width) / 2.0), y: contentHeight - 45.0 - insets.bottom), size: onlineSize) transition.updateFrame(node: self.onlineButton, frame: onlineFrame) self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight)) diff --git a/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift b/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift index 48c50b6f43..606f2431d9 100644 --- a/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift +++ b/submodules/TelegramUI/TelegramUI/GifPaneSearchContentNode.swift @@ -28,7 +28,7 @@ func paneGifSearchForQuery(account: Account, query: String, updateActivity: ((Bo } |> mapToSignal { peer -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> in if let user = peer as? TelegramUser, let botInfo = user.botInfo, let _ = botInfo.inlinePlaceholder { - let results = requestContextResults(account: account, botId: user.id, query: query, peerId: account.peerId, limit: 64) + let results = requestContextResults(account: account, botId: user.id, query: query, peerId: account.peerId, limit: 15) |> map { results -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in return { _ in return .contextRequestResult(user, results) diff --git a/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift b/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift index 5a3d511455..0e6f49d611 100644 --- a/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift +++ b/submodules/TelegramUI/TelegramUI/ListMessageDateHeader.swift @@ -105,4 +105,3 @@ final class ListMessageDateHeaderNode: ListViewItemHeaderNode { self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size) } } - diff --git a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping index 0e740b4a15..97d55f8f57 100644 Binary files a/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping and b/submodules/TelegramUI/TelegramUI/Resources/PresentationStrings.mapping differ diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index 615d605e19..e3cad1726e 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -209,6 +209,15 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti string.insert(NSAttributedString(string: paragraphBreak), at: paragraphRange.upperBound) rangeOffset += paragraphBreak.count + case .BankCard: + string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) + if underlineLinks && underlineAllLinks { + string.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue as NSNumber, range: range) + } + if nsString == nil { + nsString = text as NSString + } + string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard), value: nsString!.substring(with: range), range: range) case let .Custom(type): if type == ApplicationSpecificEntityType.Timecode { string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) diff --git a/submodules/TextFormat/Sources/TelegramAttributes.swift b/submodules/TextFormat/Sources/TelegramAttributes.swift index b05f982d82..ab276a41e3 100644 --- a/submodules/TextFormat/Sources/TelegramAttributes.swift +++ b/submodules/TextFormat/Sources/TelegramAttributes.swift @@ -37,6 +37,7 @@ public struct TelegramTextAttributes { public static let PeerTextMention = "TelegramPeerTextMention" public static let BotCommand = "TelegramBotCommand" public static let Hashtag = "TelegramHashtag" + public static let BankCard = "TelegramBankCard" public static let Timecode = "TelegramTimecode" public static let BlockQuote = "TelegramBlockQuote" } diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index bd53d7861c..051053b059 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -14,6 +14,8 @@ import TelegramUIPreferences import AccountContext import WalletUrl +private let baseTelegramMePaths = ["telegram.me", "t.me", "telegram.dog"] + public enum ParsedInternalPeerUrlParameter { case botStart(String) case groupBotStart(String) @@ -346,7 +348,6 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig public func isTelegramMeLink(_ url: String) -> Bool { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -360,7 +361,6 @@ public func isTelegramMeLink(_ url: String) -> Bool { public func parseProxyUrl(_ url: String) -> (host: String, port: Int32, username: String?, password: String?, secret: Data?)? { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -382,7 +382,6 @@ public func parseProxyUrl(_ url: String) -> (host: String, port: Int32, username public func parseStickerPackUrl(_ url: String) -> String? { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -404,7 +403,6 @@ public func parseStickerPackUrl(_ url: String) -> String? { public func parseWallpaperUrl(_ url: String) -> WallpaperUrlParameter? { let schemes = ["http://", "https://", ""] - let baseTelegramMePaths = ["telegram.me", "t.me"] for basePath in baseTelegramMePaths { for scheme in schemes { let basePrefix = scheme + basePath + "/" @@ -431,7 +429,6 @@ public func resolveUrlImpl(account: Account, url: String) -> Signal() private let centralItemTitleView = Promise() private let centralItemNavigationStyle = Promise() - private let centralItemFooterContentNode = Promise() + private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() private let centralItemAttributesDisposable = DisposableSet(); private let checkedDisposable = MetaDisposable() @@ -156,7 +156,7 @@ class WebSearchGalleryController: ViewController { self?.navigationItem.titleView = titleView })) - self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in + self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode) }, transition: .immediate) diff --git a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift index 498a758306..1f69d4ec7a 100644 --- a/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift +++ b/submodules/WebSearchUI/Sources/WebSearchVideoGalleryItem.swift @@ -534,7 +534,7 @@ final class WebSearchVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - override func footerContent() -> Signal { - return .single(self.footerContentNode) + override func footerContent() -> Signal<(GalleryFooterContentNode?, GalleryOverlayContentNode?), NoError> { + return .single((self.footerContentNode, nil)) } } diff --git a/submodules/ffmpeg/gas-preprocessor.pl b/submodules/ffmpeg/gas-preprocessor.pl new file mode 100755 index 0000000000..6da37c1f0d --- /dev/null +++ b/submodules/ffmpeg/gas-preprocessor.pl @@ -0,0 +1,1210 @@ +#!/usr/bin/env perl +# by David Conrad +# This code is licensed under GPLv2 or later; go to gnu.org to read it +# (not that it much matters for an asm preprocessor) +# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc" +use strict; + +# Apple's gas is ancient and doesn't support modern preprocessing features like +# .rept and has ugly macro syntax, among other things. Thus, this script +# implements the subset of the gas preprocessor used by x264 and ffmpeg +# that isn't supported by Apple's gas. + +my %canonical_arch = ("aarch64" => "aarch64", "arm64" => "aarch64", + "arm" => "arm", + "powerpc" => "powerpc", "ppc" => "powerpc"); + +my %comments = ("aarch64" => '//', + "arm" => '@', + "powerpc" => '#'); + +my @gcc_cmd; +my @preprocess_c_cmd; + +my $comm; +my $arch; +my $as_type = "apple-gas"; + +my $fix_unreq = $^O eq "darwin"; +my $force_thumb = 0; +my $verbose = 0; + +my $arm_cond_codes = "eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al|hs|lo"; + +my $usage_str = " +$0\n +Gas-preprocessor.pl converts assembler files using modern GNU as syntax for +Apple's ancient gas version or clang's incompatible integrated assembler. The +conversion is regularly tested for Libav, x264 and vlc. Other projects might +use different features which are not correctly handled. + +Options for this program needs to be separated with ' -- ' from the assembler +command. Following options are currently supported: + + -help - this usage text + -arch - target architecture + -as-type - one value out of {{,apple-}{gas,clang},armasm} + -fix-unreq + -no-fix-unreq + -force-thumb - assemble as thumb regardless of the input source + (note, this is incomplete and only works for sources + it explicitly was tested with) + -verbose - print executed commands +"; + +sub usage() { + print $usage_str; +} + +while (@ARGV) { + my $opt = shift; + + if ($opt =~ /^-(no-)?fix-unreq$/) { + $fix_unreq = $1 ne "no-"; + } elsif ($opt eq "-force-thumb") { + $force_thumb = 1; + } elsif ($opt eq "-verbose") { + $verbose = 1; + } elsif ($opt eq "-arch") { + $arch = shift; + die "unknown arch: '$arch'\n" if not exists $canonical_arch{$arch}; + } elsif ($opt eq "-as-type") { + $as_type = shift; + die "unknown as type: '$as_type'\n" if $as_type !~ /^((apple-)?(gas|clang)|armasm)$/; + } elsif ($opt eq "-help") { + usage(); + exit 0; + } elsif ($opt eq "--" ) { + @gcc_cmd = @ARGV; + } elsif ($opt =~ /^-/) { + die "option '$opt' is not known. See '$0 -help' for usage information\n"; + } else { + push @gcc_cmd, $opt, @ARGV; + } + last if (@gcc_cmd); +} + +if (grep /\.c$/, @gcc_cmd) { + # C file (inline asm?) - compile + @preprocess_c_cmd = (@gcc_cmd, "-S"); +} elsif (grep /\.[sS]$/, @gcc_cmd) { + # asm file, just do C preprocessor + @preprocess_c_cmd = (@gcc_cmd, "-E"); +} elsif (grep /-(v|h|-version|dumpversion)/, @gcc_cmd) { + # pass -v/--version along, used during probing. Matching '-v' might have + # uninteded results but it doesn't matter much if gas-preprocessor or + # the compiler fails. + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + exec(@gcc_cmd); +} else { + die "Unrecognized input filetype"; +} +if ($as_type eq "armasm") { + + $preprocess_c_cmd[0] = "cpp"; + push(@preprocess_c_cmd, "-undef"); + # Normally a preprocessor for windows would predefine _WIN32, + # but we're using any generic system-agnostic preprocessor "cpp" + # with -undef (to avoid getting predefined variables from the host + # system in cross compilation cases), so manually define it here. + push(@preprocess_c_cmd, "-D_WIN32"); + + @preprocess_c_cmd = grep ! /^-nologo$/, @preprocess_c_cmd; + # Remove -ignore XX parameter pairs from preprocess_c_cmd + my $index = 1; + while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-ignore" and $index + 1 < $#preprocess_c_cmd) { + splice(@preprocess_c_cmd, $index, 2); + next; + } + $index++; + } + if (grep /^-MM$/, @preprocess_c_cmd) { + print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; + system(@preprocess_c_cmd) == 0 or die "Error running preprocessor"; + exit 0; + } +} + +# if compiling, avoid creating an output file named '-.o' +if ((grep /^-c$/, @gcc_cmd) && !(grep /^-o/, @gcc_cmd)) { + foreach my $i (@gcc_cmd) { + if ($i =~ /\.[csS]$/) { + my $outputfile = $i; + $outputfile =~ s/\.[csS]$/.o/; + push(@gcc_cmd, "-o"); + push(@gcc_cmd, $outputfile); + last; + } + } +} +# replace only the '-o' argument with '-', avoids rewriting the make dependency +# target specified with -MT to '-' +my $index = 1; +while ($index < $#preprocess_c_cmd) { + if ($preprocess_c_cmd[$index] eq "-o") { + $index++; + $preprocess_c_cmd[$index] = "-"; + } + $index++; +} + +my $tempfile; +if ($as_type ne "armasm") { + @gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd; +} else { + @preprocess_c_cmd = grep ! /^-c$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-m/, @preprocess_c_cmd; + + @preprocess_c_cmd = grep ! /^-G/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-W/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-Z/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-fp/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-EHsc$/, @preprocess_c_cmd; + @preprocess_c_cmd = grep ! /^-O/, @preprocess_c_cmd; + + @gcc_cmd = grep ! /^-G/, @gcc_cmd; + @gcc_cmd = grep ! /^-W/, @gcc_cmd; + @gcc_cmd = grep ! /^-Z/, @gcc_cmd; + @gcc_cmd = grep ! /^-fp/, @gcc_cmd; + @gcc_cmd = grep ! /^-EHsc$/, @gcc_cmd; + @gcc_cmd = grep ! /^-O/, @gcc_cmd; + + my @outfiles = grep /\.(o|obj)$/, @gcc_cmd; + $tempfile = $outfiles[0].".asm"; + + # Remove most parameters from gcc_cmd, which actually is the armasm command, + # which doesn't support any of the common compiler/preprocessor options. + @gcc_cmd = grep ! /^-D/, @gcc_cmd; + @gcc_cmd = grep ! /^-U/, @gcc_cmd; + @gcc_cmd = grep ! /^-m/, @gcc_cmd; + @gcc_cmd = grep ! /^-M/, @gcc_cmd; + @gcc_cmd = grep ! /^-c$/, @gcc_cmd; + @gcc_cmd = grep ! /^-I/, @gcc_cmd; + @gcc_cmd = map { /\.S$/ ? $tempfile : $_ } @gcc_cmd; +} + +# detect architecture from gcc binary name +if (!$arch) { + if ($gcc_cmd[0] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } else { + # look for -arch flag + foreach my $i (1 .. $#gcc_cmd-1) { + if ($gcc_cmd[$i] eq "-arch" and + $gcc_cmd[$i+1] =~ /(arm64|aarch64|arm|powerpc|ppc)/) { + $arch = $1; + } + } + } +} + +# assume we're not cross-compiling if no -arch or the binary doesn't have the arch name +$arch = qx/arch/ if (!$arch); + +die "Unknown target architecture '$arch'" if not exists $canonical_arch{$arch}; + +$arch = $canonical_arch{$arch}; +$comm = $comments{$arch}; +my $inputcomm = $comm; +$comm = ";" if $as_type =~ /armasm/; + +my %ppc_spr = (ctr => 9, + vrsave => 256); + +print STDERR join(" ", @preprocess_c_cmd)."\n" if $verbose; +open(INPUT, "-|", @preprocess_c_cmd) || die "Error running preprocessor"; + +if ($ENV{GASPP_DEBUG}) { + open(ASMFILE, ">&STDOUT"); +} else { + if ($as_type ne "armasm") { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler"; + } else { + open(ASMFILE, ">", $tempfile); + } +} + +my $current_macro = ''; +my $macro_level = 0; +my $rept_level = 0; +my %macro_lines; +my %macro_args; +my %macro_args_default; +my $macro_count = 0; +my $altmacro = 0; +my $in_irp = 0; + +my $num_repts; +my @rept_lines; + +my @irp_args; +my $irp_param; + +my @ifstack; + +my %symbols; + +my @sections; + +my %literal_labels; # for ldr , = +my $literal_num = 0; +my $literal_expr = ".word"; +$literal_expr = ".quad" if $arch eq "aarch64"; + +my $thumb = 0; + +my %thumb_labels; +my %call_targets; +my %import_symbols; + +my %neon_alias_reg; +my %neon_alias_type; + +my $temp_label_next = 0; +my %last_temp_labels; +my %next_temp_labels; + +my %labels_seen; + +my %aarch64_req_alias; + +if ($force_thumb) { + parse_line(".thumb\n"); +} + +# pass 1: parse .macro +# note that the handling of arguments is probably overly permissive vs. gas +# but it should be the same for valid cases +while () { + # remove lines starting with '#', preprocessing is done, '#' at start of + # the line indicates a comment for all supported archs (aarch64, arm, ppc + # and x86). Also strips line number comments but since they are off anyway + # it is no loss. + s/^\s*#.*$//; + # remove all comments (to avoid interfering with evaluating directives) + s/(? 0) { + $ifstack[-1] = -$ifstack[-1]; + } + return 1; + } elsif ($line =~ /\.else/) { + $ifstack[-1] = !$ifstack[-1]; + return 1; + } elsif (handle_if($line)) { + return 1; + } + } + + # discard lines in false .if blocks + foreach my $i (0 .. $#ifstack) { + if ($ifstack[$i] <= 0) { + return 1; + } + } + } + return 0; +} + +sub parse_line { + my $line = $_[0]; + + return if (parse_if_line($line)); + + if (scalar(@rept_lines) == 0) { + if ($line =~ /\.macro/) { + $macro_level++; + if ($macro_level > 1 && !$current_macro) { + die "nested macros but we don't have master macro"; + } + } elsif ($line =~ /\.endm/) { + $macro_level--; + if ($macro_level < 0) { + die "unmatched .endm"; + } elsif ($macro_level == 0) { + $current_macro = ''; + return; + } + } + } + + if ($macro_level == 0) { + if ($line =~ /\.(rept|irp)/) { + $rept_level++; + } elsif ($line =~ /.endr/) { + $rept_level--; + } + } + + if ($macro_level > 1) { + push(@{$macro_lines{$current_macro}}, $line); + } elsif (scalar(@rept_lines) and $rept_level >= 1) { + push(@rept_lines, $line); + } elsif ($macro_level == 0) { + expand_macros($line); + } else { + if ($line =~ /\.macro\s+([\d\w\.]+)\s*,?\s*(.*)/) { + $current_macro = $1; + + # commas in the argument list are optional, so only use whitespace as the separator + my $arglist = $2; + $arglist =~ s/,/ /g; + + my @args = split(/\s+/, $arglist); + foreach my $i (0 .. $#args) { + my @argpair = split(/=/, $args[$i]); + $macro_args{$current_macro}[$i] = $argpair[0]; + $argpair[0] =~ s/:vararg$//; + $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1]; + } + # ensure %macro_lines has the macro name added as a key + $macro_lines{$current_macro} = []; + + } elsif ($current_macro) { + push(@{$macro_lines{$current_macro}}, $line); + } else { + die "macro level without a macro name"; + } + } +} + +sub handle_set { + my $line = $_[0]; + if ($line =~ /\.(?:set|equ)\s+(\S*)\s*,\s*(.*)/) { + $symbols{$1} = eval_expr($2); + return 1; + } + return 0; +} + +sub expand_macros { + my $line = $_[0]; + + # handle .if directives; apple's assembler doesn't support important non-basic ones + # evaluating them is also needed to handle recursive macros + if (handle_if($line)) { + return; + } + + if (/\.purgem\s+([\d\w\.]+)/) { + delete $macro_lines{$1}; + delete $macro_args{$1}; + delete $macro_args_default{$1}; + return; + } + + if ($line =~ /\.altmacro/) { + $altmacro = 1; + return; + } + + if ($line =~ /\.noaltmacro/) { + $altmacro = 0; + return; + } + + $line =~ s/\%([^,]*)/eval_expr($1)/eg if $altmacro; + + # Strip out the .set lines from the armasm output + return if (handle_set($line) and $as_type eq "armasm"); + + if ($line =~ /\.rept\s+(.*)/) { + $num_repts = $1; + @rept_lines = ("\n"); + + # handle the possibility of repeating another directive on the same line + # .endr on the same line is not valid, I don't know if a non-directive is + if ($num_repts =~ s/(\.\w+.*)//) { + push(@rept_lines, "$1\n"); + } + $num_repts = eval_expr($num_repts); + } elsif ($line =~ /\.irp\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + # only use whitespace as the separator + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(/\s+/, $irp_arglist); + } elsif ($line =~ /\.irpc\s+([\d\w\.]+)\s*(.*)/) { + $in_irp = 1; + $num_repts = 1; + @rept_lines = ("\n"); + $irp_param = $1; + + my $irp_arglist = $2; + $irp_arglist =~ s/,/ /g; + $irp_arglist =~ s/^\s+//; + @irp_args = split(//, $irp_arglist); + } elsif ($line =~ /\.endr/) { + my @prev_rept_lines = @rept_lines; + my $prev_in_irp = $in_irp; + my @prev_irp_args = @irp_args; + my $prev_irp_param = $irp_param; + my $prev_num_repts = $num_repts; + @rept_lines = (); + $in_irp = 0; + @irp_args = ''; + + if ($prev_in_irp != 0) { + foreach my $i (@prev_irp_args) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + $line =~ s/\\$prev_irp_param/$i/g; + $line =~ s/\\\(\)//g; # remove \() + parse_line($line); + } + } + } else { + for (1 .. $prev_num_repts) { + foreach my $origline (@prev_rept_lines) { + my $line = $origline; + parse_line($line); + } + } + } + } elsif ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) { + handle_serialized_line($1); + my $macro = $2; + + # commas are optional here too, but are syntactically important because + # parameters can be blank + my @arglist = split(/,/, $3); + my @args; + my @args_seperator; + + my $comma_sep_required = 0; + foreach (@arglist) { + # allow arithmetic/shift operators in macro arguments + $_ =~ s/\s*(\+|-|\*|\/|<<|>>|<|>)\s*/$1/g; + + my @whitespace_split = split(/\s+/, $_); + if (!@whitespace_split) { + push(@args, ''); + push(@args_seperator, ''); + } else { + foreach (@whitespace_split) { + #print ("arglist = \"$_\"\n"); + if (length($_)) { + push(@args, $_); + my $sep = $comma_sep_required ? "," : " "; + push(@args_seperator, $sep); + #print ("sep = \"$sep\", arg = \"$_\"\n"); + $comma_sep_required = 0; + } + } + } + + $comma_sep_required = 1; + } + + my %replacements; + if ($macro_args_default{$macro}){ + %replacements = %{$macro_args_default{$macro}}; + } + + # construct hashtable of text to replace + foreach my $i (0 .. $#args) { + my $argname = $macro_args{$macro}[$i]; + my @macro_args = @{ $macro_args{$macro} }; + if ($args[$i] =~ m/=/) { + # arg=val references the argument name + # XXX: I'm not sure what the expected behaviour if a lot of + # these are mixed with unnamed args + my @named_arg = split(/=/, $args[$i]); + $replacements{$named_arg[0]} = $named_arg[1]; + } elsif ($i > $#{$macro_args{$macro}}) { + # more args given than the macro has named args + # XXX: is vararg allowed on arguments before the last? + $argname = $macro_args{$macro}[-1]; + if ($argname =~ s/:vararg$//) { + #print "macro = $macro, args[$i] = $args[$i], args_seperator=@args_seperator, argname = $argname, arglist[$i] = $arglist[$i], arglist = @arglist, args=@args, macro_args=@macro_args\n"; + #$replacements{$argname} .= ", $args[$i]"; + $replacements{$argname} .= "$args_seperator[$i] $args[$i]"; + } else { + die "Too many arguments to macro $macro"; + } + } else { + $argname =~ s/:vararg$//; + $replacements{$argname} = $args[$i]; + } + } + + my $count = $macro_count++; + + # apply replacements as regex + foreach (@{$macro_lines{$macro}}) { + my $macro_line = $_; + # do replacements by longest first, this avoids wrong replacement + # when argument names are subsets of each other + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\\$_/$replacements{$_}/g; + } + if ($altmacro) { + foreach (reverse sort {length $a <=> length $b} keys %replacements) { + $macro_line =~ s/\b$_\b/$replacements{$_}/g; + } + } + $macro_line =~ s/\\\@/$count/g; + $macro_line =~ s/\\\(\)//g; # remove \() + parse_line($macro_line); + } + } else { + handle_serialized_line($line); + } +} + +sub is_arm_register { + my $name = $_[0]; + if ($name eq "lr" or + $name eq "ip" or + $name =~ /^[rav]\d+$/) { + return 1; + } + return 0; +} + +sub is_aarch64_register { + my $name = $_[0]; + if ($name =~ /^[xw]\d+$/) { + return 1; + } + return 0; +} + +sub handle_local_label { + my $line = $_[0]; + my $num = $_[1]; + my $dir = $_[2]; + my $target = "$num$dir"; + if ($dir eq "b") { + $line =~ s/\b$target\b/$last_temp_labels{$num}/g; + } else { + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + push(@{$next_temp_labels{$num}}, $name); + $line =~ s/\b$target\b/$name/g; + } + return $line; +} + +sub handle_serialized_line { + my $line = $_[0]; + + # handle .previous (only with regard to .section not .subsection) + if ($line =~ /\.(section|text|const_data)/) { + push(@sections, $line); + } elsif ($line =~ /\.previous/) { + if (!$sections[-2]) { + die ".previous without a previous section"; + } + $line = $sections[-2]; + push(@sections, $line); + } + + $thumb = 1 if $line =~ /\.code\s+16|\.thumb/; + $thumb = 0 if $line =~ /\.code\s+32|\.arm/; + + # handle ldr , = + if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/ and $as_type ne "armasm") { + my $label = $literal_labels{$3}; + if (!$label) { + $label = "Literal_$literal_num"; + $literal_num++; + $literal_labels{$3} = $label; + } + $line = "$1 ldr$2, $label\n"; + } elsif ($line =~ /\.ltorg/ and $as_type ne "armasm") { + $line .= ".align 2\n"; + foreach my $literal (keys %literal_labels) { + $line .= "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + %literal_labels = (); + } + + # handle GNU as pc-relative relocations for adrp/add + if ($line =~ /(.*)\s*adrp([\w\s\d]+)\s*,\s*#?:pg_hi21:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 adrp$2, ${3}\@PAGE\n"; + } elsif ($line =~ /(.*)\s*add([\w\s\d]+)\s*,([\w\s\d]+)\s*,\s*#?:lo12:([^\s]+)/ and $as_type =~ /^apple-/) { + $line = "$1 add$2, $3, ${4}\@PAGEOFF\n"; + } + + # thumb add with large immediate needs explicit add.w + if ($thumb and $line =~ /add\s+.*#([^@]+)/) { + $line =~ s/add/add.w/ if eval_expr($1) > 255; + } + + # mach-o local symbol names start with L (no dot) + $line =~ s/(? with ic as conditional code + if ($cond =~ /^(|$arm_cond_codes)$/) { + if (exists $thumb_labels{$label}) { + print ASMFILE ".thumb_func $label\n"; + } else { + $call_targets{$label}++; + } + } + } + + # @l -> lo16() @ha -> ha16() + $line =~ s/,\s+([^,]+)\@l\b/, lo16($1)/g; + $line =~ s/,\s+([^,]+)\@ha\b/, ha16($1)/g; + + # move to/from SPR + if ($line =~ /(\s+)(m[ft])([a-z]+)\s+(\w+)/ and exists $ppc_spr{$3}) { + if ($2 eq 'mt') { + $line = "$1${2}spr $ppc_spr{$3}, $4\n"; + } else { + $line = "$1${2}spr $4, $ppc_spr{$3}\n"; + } + } + + if ($line =~ /\.unreq\s+(.*)/) { + if (defined $neon_alias_reg{$1}) { + delete $neon_alias_reg{$1}; + delete $neon_alias_type{$1}; + return; + } elsif (defined $aarch64_req_alias{$1}) { + delete $aarch64_req_alias{$1}; + return; + } + } + # old gas versions store upper and lower case names on .req, + # but they remove only one on .unreq + if ($fix_unreq) { + if ($line =~ /\.unreq\s+(.*)/) { + $line = ".unreq " . lc($1) . "\n"; + $line .= ".unreq " . uc($1) . "\n"; + } + } + + if ($line =~ /(\w+)\s+\.(dn|qn)\s+(\w+)(?:\.(\w+))?(\[\d+\])?/) { + $neon_alias_reg{$1} = "$3$5"; + $neon_alias_type{$1} = $4; + return; + } + if (scalar keys %neon_alias_reg > 0 && $line =~ /^\s+v\w+/) { + # This line seems to possibly have a neon instruction + foreach (keys %neon_alias_reg) { + my $alias = $_; + # Require the register alias to match as an invididual word, not as a substring + # of a larger word-token. + if ($line =~ /\b$alias\b/) { + $line =~ s/\b$alias\b/$neon_alias_reg{$alias}/g; + # Add the type suffix. If multiple aliases match on the same line, + # only do this replacement the first time (a vfoo.bar string won't match v\w+). + $line =~ s/^(\s+)(v\w+)(\s+)/$1$2.$neon_alias_type{$alias}$3/; + } + } + } + + if ($arch eq "aarch64" or $as_type eq "armasm") { + # clang's integrated aarch64 assembler in Xcode 5 does not support .req/.unreq + if ($line =~ /\b(\w+)\s+\.req\s+(\w+)\b/) { + $aarch64_req_alias{$1} = $2; + return; + } + foreach (keys %aarch64_req_alias) { + my $alias = $_; + # recursively resolve aliases + my $resolved = $aarch64_req_alias{$alias}; + while (defined $aarch64_req_alias{$resolved}) { + $resolved = $aarch64_req_alias{$resolved}; + } + $line =~ s/\b$alias\b/$resolved/g; + } + } + if ($arch eq "aarch64") { + # fix missing aarch64 instructions in Xcode 5.1 (beta3) + # mov with vector arguments is not supported, use alias orr instead + if ($line =~ /^(\d+:)?\s*mov\s+(v\d[\.{}\[\]\w]+),\s*(v\d[\.{}\[\]\w]+)\b\s*$/) { + $line = "$1 orr $2, $3, $3\n"; + } + # movi 16, 32 bit shifted variant, shift is optional + if ($line =~ /^(\d+:)?\s*movi\s+(v[0-3]?\d\.(?:2|4|8)[hsHS])\s*,\s*(#\w+)\b\s*$/) { + $line = "$1 movi $2, $3, lsl #0\n"; + } + # Xcode 5 misses the alias uxtl. Replace it with the more general ushll. + # Clang 3.4 misses the alias sxtl too. Replace it with the more general sshll. + # armasm64 also misses these instructions. + if ($line =~ /^(\d+:)?\s*(s|u)xtl(2)?\s+(v[0-3]?\d\.[248][hsdHSD])\s*,\s*(v[0-3]?\d\.(?:2|4|8|16)[bhsBHS])\b\s*$/) { + $line = "$1 $2shll$3 $4, $5, #0\n"; + } + # clang 3.4 and armasm64 do not automatically use shifted immediates in add/sub + if (($as_type eq "clang" or $as_type eq "armasm") and + $line =~ /^(\d+:)?(\s*(?:add|sub)s?) ([^#l]+)#([\d\+\-\*\/ <>]+)\s*$/) { + my $imm = eval $4; + if ($imm > 4095 and not ($imm & 4095)) { + $line = "$1 $2 $3#" . ($imm >> 12) . ", lsl #12\n"; + } + } + if ($ENV{GASPP_FIX_XCODE5}) { + if ($line =~ /^\s*bsl\b/) { + $line =~ s/\b(bsl)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.$3\b/$1/g; + } + if ($line =~ /^\s*saddl2?\b/) { + $line =~ s/\b(saddl2?)(\s+v[0-3]?\d\.(\w+))\b/$1.$3$2/; + $line =~ s/\b(v[0-3]?\d)\.\w+\b/$1/g; + } + if ($line =~ /^\s*dup\b.*\]$/) { + $line =~ s/\bdup(\s+v[0-3]?\d)\.(\w+)\b/dup.$2$1/g; + $line =~ s/\b(v[0-3]?\d)\.[bhsdBHSD](\[\d\])$/$1$2/g; + } + } + } + + if ($as_type eq "armasm") { + # Also replace variables set by .set + foreach (keys %symbols) { + my $sym = $_; + $line =~ s/\b$sym\b/$symbols{$sym}/g; + } + + # Handle function declarations and keep track of the declared labels + if ($line =~ s/^\s*\.func\s+(\w+)/$1 PROC/) { + $labels_seen{$1} = 1; + } + + if ($line =~ s/^\s*(\d+)://) { + # Convert local labels into unique labels. armasm (at least in + # RVCT) has something similar, but still different enough. + # By converting to unique labels we avoid any possible + # incompatibilities. + + my $num = $1; + foreach (@{$next_temp_labels{$num}}) { + $line = "$_\n" . $line; + } + @next_temp_labels{$num} = (); + my $name = "temp_label_$temp_label_next"; + $temp_label_next++; + # The matching regexp above removes the label from the start of + # the line (which might contain an instruction as well), readd + # it on a separate line above it. + $line = "$name:\n" . $line; + $last_temp_labels{$num} = $name; + } + + if ($line =~ s/^\s*(\w+):/$1/) { + # Skip labels that have already been declared with a PROC, + # labels must not be declared multiple times. + return if (defined $labels_seen{$1}); + $labels_seen{$1} = 1; + } elsif ($line !~ /(\w+) PROC/) { + # If not a label, make sure the line starts with whitespace, + # otherwise ms armasm interprets it incorrectly. + $line =~ s/^[\.\w]/\t$&/; + } + + + # Check branch instructions + if ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(bl?x?\.?([^\s]{2})?(\.w)?)\s+(\w+)/) { + my $instr = $2; + my $cond = $3; + my $width = $4; + my $target = $5; + # Don't interpret e.g. bic as b with ic as conditional code + if ($cond !~ /^(|$arm_cond_codes)$/) { + # Not actually a branch + } elsif ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + $line =~ s/\b$instr\b/$&.w/ if $width eq "" and $arch eq "arm"; + } elsif (($arch eq "arm" and !is_arm_register($target)) or + ($arch eq "aarch64" and !is_aarch64_register($target))) { + $call_targets{$target}++; + } + } elsif ($line =~ /(?:^|\n)\s*(\w+\s*:\s*)?(cbn?z|adr|tbz)\s+(\w+)\s*,(\s*#\d+\s*,)?\s*(\w+)/) { + my $instr = $2; + my $reg = $3; + my $bit = $4; + my $target = $5; + if ($target =~ /^(\d+)([bf])$/) { + # The target is a local label + $line = handle_local_label($line, $1, $2); + } else { + $call_targets{$target}++; + } + # Convert tbz with a wX register into an xX register, + # due to armasm64 bugs/limitations. + if ($instr eq "tbz" and $reg =~ /w\d+/) { + my $xreg = $reg; + $xreg =~ s/w/x/; + $line =~ s/\b$reg\b/$xreg/; + } + } elsif ($line =~ /^\s*.h?word.*\b\d+[bf]\b/) { + while ($line =~ /\b(\d+)([bf])\b/g) { + $line = handle_local_label($line, $1, $2); + } + } + + # ALIGN in armasm syntax is the actual number of bytes + if ($line =~ /\.(?:p2)?align\s+(\d+)/) { + my $align = 1 << $1; + $line =~ s/\.(?:p2)?align\s+(\d+)/ALIGN $align/; + } + # Convert gas style [r0, :128] into armasm [r0@128] alignment specification + $line =~ s/\[([^\[,]+),?\s*:(\d+)\]/[$1\@$2]/g; + + # armasm treats logical values {TRUE} and {FALSE} separately from + # numeric values - logical operators and values can't be intermixed + # with numerical values. Evaluate ! and (a <> b) into numbers, + # let the assembler evaluate the rest of the expressions. This current + # only works for cases when ! and <> are used with actual constant numbers, + # we don't evaluate subexpressions here. + + # Evaluate ! + while ($line =~ /!\s*(\d+)/g) { + my $val = ($1 != 0) ? 0 : 1; + $line =~ s/!(\d+)/$val/; + } + # Evaluate (a > b) + while ($line =~ /\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/) { + my $val; + if ($2 eq "<") { + $val = ($1 < $3) ? 1 : 0; + } else { + $val = ($1 > $3) ? 1 : 0; + } + $line =~ s/\(\s*(\d+)\s*([<>])\s*(\d+)\s*\)/$val/; + } + + if ($arch eq "arm") { + # Change a movw... #:lower16: into a mov32 pseudoinstruction + $line =~ s/^(\s*)movw(\s+\w+\s*,\s*)\#:lower16:(.*)$/$1mov32$2$3/; + # and remove the following, matching movt completely + $line =~ s/^\s*movt\s+\w+\s*,\s*\#:upper16:.*$//; + + if ($line =~ /^\s*mov32\s+\w+,\s*([a-zA-Z]\w*)/) { + $import_symbols{$1}++; + } + + # Misc bugs/deficiencies: + # armasm seems unable to parse e.g. "vmov s0, s1" without a type + # qualifier, thus add .f32. + $line =~ s/^(\s+(?:vmov|vadd))(\s+s\d+\s*,\s*s\d+)/$1.f32$2/; + } elsif ($arch eq "aarch64") { + # Convert ext into ext8; armasm64 seems to require it named as ext8. + $line =~ s/^(\s+)ext(\s+)/$1ext8$2/; + + # Pick up targets from ldr x0, =sym+offset + if ($line =~ /^\s*ldr\s+(\w+)\s*,\s*=([a-zA-Z]\w*)(.*)$/) { + my $reg = $1; + my $sym = $2; + my $offset = eval_expr($3); + if ($offset < 0 and $ENV{GASPP_ARMASM64_SKIP_NEG_OFFSET}) { + # armasm64 in VS < 15.6 is buggy with ldr x0, =sym+offset where the + # offset is a negative value; it does write a negative + # offset into the literal pool as it should, but the + # negative offset only covers the lower 32 bit of the 64 + # bit literal/relocation. + # Thus remove the offset and apply it manually with a sub + # afterwards. + $offset = -$offset; + $line = "\tldr $reg, =$sym\n\tsub $reg, $reg, #$offset\n"; + } + $import_symbols{$sym}++; + } + + # armasm64 (currently) doesn't support offsets on adrp targets, + # even though the COFF format relocations (and the linker) + # supports it. Therefore strip out the offsets from adrp and + # add :lo12: (in case future armasm64 would start handling it) + # and add an extra explicit add instruction for the offset. + if ($line =~ s/(adrp\s+\w+\s*,\s*(\w+))([\d\+\-\*\/\(\) <>]+)?/\1/) { + $import_symbols{$2}++; + } + if ($line =~ s/(add\s+(\w+)\s*,\s*\w+\s*,\s*):lo12:(\w+)([\d\+\-\*\/\(\) <>]+)?/\1\3/) { + my $reg = $2; + my $sym = $3; + my $offset = eval_expr($4); + $line .= "\tadd $reg, $reg, #$offset\n" if $offset > 0; + $import_symbols{$sym}++; + } + + # Convert e.g. "add x0, x0, w0, uxtw" into "add x0, x0, w0, uxtw #0", + # or "ldr x0, [x0, w0, uxtw]" into "ldr x0, [x0, w0, uxtw #0]". + $line =~ s/(uxt[whb]|sxt[whb])(\s*\]?\s*)$/\1 #0\2/i; + + # Convert "mov x0, v0.d[0]" into "umov x0, v0.d[0]" + $line =~ s/\bmov\s+[xw]\d+\s*,\s*v\d+\.[ds]/u$&/i; + + # Convert "ccmp w0, #0, #0, ne" into "ccmpne w0, #0, #0", + # and "csel w0, w0, w0, ne" into "cselne w0, w0, w0". + $line =~ s/(ccmp|csel)\s+([xw]\w+)\s*,\s*([xw#]\w+)\s*,\s*([xw#]\w+)\s*,\s*($arm_cond_codes)/\1\5 \2, \3, \4/; + + # Convert "cinc w0, w0, ne" into "cincne w0, w0". + $line =~ s/(cinc)\s+([xw]\w+)\s*,\s*([xw]\w+)\s*,\s*($arm_cond_codes)/\1\4 \2, \3/; + + # Convert "cset w0, lo" into "csetlo w0" + $line =~ s/(cset)\s+([xw]\w+)\s*,\s*($arm_cond_codes)/\1\3 \2/; + + if ($ENV{GASPP_ARMASM64_SKIP_PRFUM}) { + # Strip out prfum; armasm64 (VS < 15.5) fails to assemble any + # variant/combination of prfum tested so far, but since it is + # a prefetch instruction it can be skipped without changing + # results. + $line =~ s/prfum.*\]//; + } + + # Convert "ldrb w0, [x0, #-1]" into "ldurb w0, [x0, #-1]". + # Don't do this for forms with writeback though. + if ($line =~ /(ld|st)(r[bh]?)\s+(\w+)\s*,\s*\[\s*(\w+)\s*,\s*#([^\]]+)\s*\][^!]/) { + my $instr = $1; + my $suffix = $2; + my $target = $3; + my $base = $4; + my $offset = eval_expr($5); + if ($offset < 0) { + $line =~ s/$instr$suffix/${instr}u$suffix/; + } + } + + if ($ENV{GASPP_ARMASM64_INVERT_SCALE}) { + # Instructions like fcvtzs and scvtf store the scale value + # inverted in the opcode (stored as 64 - scale), but armasm64 + # in VS < 15.5 stores it as-is. Thus convert from + # "fcvtzs w0, s0, #8" into "fcvtzs w0, s0, #56". + if ($line =~ /(?:fcvtzs|scvtf)\s+(\w+)\s*,\s*(\w+)\s*,\s*#(\d+)/) { + my $scale = $3; + my $inverted_scale = 64 - $3; + $line =~ s/#$scale/#$inverted_scale/; + } + } + + # Convert "ld1 {v0.4h-v3.4h}" into "ld1 {v0.4h,v1.4h,v2.4h,v3.4h}" + if ($line =~ /(?:ld|st)\d\s+({\s*v(\d+)\.(\d[bhsdBHSD])\s*-\s*v(\d+)\.(\d[bhsdBHSD])\s*})/) { + my $regspec = $1; + my $reg1 = $2; + my $layout1 = $3; + my $reg2 = $4; + my $layout2 = $5; + if ($layout1 eq $layout2) { + my $new_regspec = "{"; + foreach my $i ($reg1 .. $reg2) { + $new_regspec .= "," if ($i > $reg1); + $new_regspec .= "v$i.$layout1"; + } + $new_regspec .= "}"; + $line =~ s/$regspec/$new_regspec/; + } + } + } + # armasm is unable to parse &0x - add spacing + $line =~ s/&0x/& 0x/g; + } + + if ($force_thumb) { + # Convert register post indexing to a separate add instruction. + # This converts e.g. "ldr r0, [r1], r2" into "ldr r0, [r1]", + # "add r1, r1, r2". + $line =~ s/((?:ldr|str)[bh]?)\s+(\w+),\s*\[(\w+)\],\s*(\w+)/$1 $2, [$3]\n\tadd $3, $3, $4/g; + + # Convert "mov pc, lr" into "bx lr", since the former only works + # for switching from arm to thumb (and only in armv7), but not + # from thumb to arm. + $line =~ s/mov\s*pc\s*,\s*lr/bx lr/g; + + # Convert stmdb/ldmia/stmfd/ldmfd/ldm with only one register into a plain str/ldr with post-increment/decrement. + # Wide thumb2 encoding requires at least two registers in register list while all other encodings support one register too. + $line =~ s/stm(?:db|fd)\s+sp!\s*,\s*\{([^,-]+)\}/str $1, [sp, #-4]!/g; + $line =~ s/ldm(?:ia|fd)?\s+sp!\s*,\s*\{([^,-]+)\}/ldr $1, [sp], #4/g; + + # Convert muls into mul+cmp + $line =~ s/muls\s+(\w+),\s*(\w+)\,\s*(\w+)/mul $1, $2, $3\n\tcmp $1, #0/g; + + # Convert "and r0, sp, #xx" into "mov r0, sp", "and r0, r0, #xx" + $line =~ s/and\s+(\w+),\s*(sp|r13)\,\s*#(\w+)/mov $1, $2\n\tand $1, $1, #$3/g; + + # Convert "ldr r0, [r0, r1, lsl #6]" where the shift is >3 (which + # can't be handled in thumb) into "add r0, r0, r1, lsl #6", + # "ldr r0, [r0]", for the special case where the same address is + # used as base and target for the ldr. + if ($line =~ /(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/ and $4 > 3) { + $line =~ s/(ldr[bh]?)\s+(\w+),\s*\[\2,\s*(\w+),\s*lsl\s*#(\w+)\]/add $2, $2, $3, lsl #$4\n\t$1 $2, [$2]/; + } + + $line =~ s/\.arm/.thumb/x; + } + + # comment out unsupported directives + $line =~ s/\.type/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.func/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.endfunc/ENDP/x if $as_type =~ /armasm/; + $line =~ s/\.ltorg/$comm$&/x if $as_type =~ /^(apple-|clang)/; + $line =~ s/\.ltorg/LTORG/x if $as_type eq "armasm"; + $line =~ s/\.size/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.fpu/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/\.arch/$comm$&/x if $as_type =~ /^(apple-|clang|armasm)/; + $line =~ s/\.object_arch/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + $line =~ s/.section\s+.note.GNU-stack.*/$comm$&/x if $as_type =~ /^(apple-|armasm)/; + + $line =~ s/\.syntax/$comm$&/x if $as_type =~ /armasm/; + + $line =~ s/\.hword/.short/x; + + if ($as_type =~ /^apple-/) { + # the syntax for these is a little different + $line =~ s/\.global/.globl/x; + # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const + $line =~ s/(.*)\.rodata/.const_data/x; + $line =~ s/\.int/.long/x; + $line =~ s/\.float/.single/x; + } + if ($as_type eq "apple-gas") { + $line =~ s/vmrs\s+APSR_nzcv/fmrx r15/x; + } + if ($as_type eq "armasm") { + $line =~ s/\.global/EXPORT/x; + $line =~ s/\.extern/IMPORT/x; + $line =~ s/\.int/dcd/x; + $line =~ s/\.long/dcd/x; + $line =~ s/\.float/dcfs/x; + $line =~ s/\.word/dcd/x; + $line =~ s/\.short/dcw/x; + $line =~ s/\.byte/dcb/x; + $line =~ s/\.quad/dcq/x; + $line =~ s/\.ascii/dcb/x; + $line =~ s/\.asciz(.*)$/dcb\1,0/x; + $line =~ s/\.thumb/THUMB/x; + $line =~ s/\.arm/ARM/x; + # The alignment in AREA is the power of two, just as .align in gas + $line =~ s/\.text/AREA |.text|, CODE, READONLY, ALIGN=4, CODEALIGN/; + $line =~ s/(\s*)(.*)\.ro?data/$1AREA |.rdata|, DATA, READONLY, ALIGN=5/; + $line =~ s/\.data/AREA |.data|, DATA, ALIGN=5/; + } + if ($as_type eq "armasm" and $arch eq "arm") { + $line =~ s/fmxr/vmsr/; + $line =~ s/fmrx/vmrs/; + $line =~ s/fadds/vadd.f32/; + } + if ($as_type eq "armasm" and $arch eq "aarch64") { + # Convert "b.eq" into "beq" + $line =~ s/\bb\.($arm_cond_codes)\b/b\1/; + } + + # catch unknown section names that aren't mach-o style (with a comma) + if ($as_type =~ /apple-/ and $line =~ /.section ([^,]*)$/) { + die ".section $1 unsupported; figure out the mach-o section name and add it"; + } + + print ASMFILE $line; +} + +if ($as_type ne "armasm") { + print ASMFILE ".text\n"; + print ASMFILE ".align 2\n"; + foreach my $literal (keys %literal_labels) { + print ASMFILE "$literal_labels{$literal}:\n $literal_expr $literal\n"; + } + + map print(ASMFILE ".thumb_func $_\n"), + grep exists $thumb_labels{$_}, keys %call_targets; +} else { + map print(ASMFILE "\tIMPORT $_\n"), + grep ! exists $labels_seen{$_}, (keys %call_targets, keys %import_symbols); + + print ASMFILE "\tEND\n"; +} + +close(INPUT) or exit 1; +close(ASMFILE) or exit 1; +if ($as_type eq "armasm" and ! defined $ENV{GASPP_DEBUG}) { + print STDERR join(" ", @gcc_cmd)."\n" if $verbose; + system(@gcc_cmd) == 0 or die "Error running assembler"; +} + +END { + unlink($tempfile) if defined $tempfile; +} +#exit 1