Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

# Conflicts:
#	submodules/TelegramCore/Sources/ChannelStatistics.swift
This commit is contained in:
overtake 2020-02-25 11:40:35 +04:00
commit e38a69235d
42 changed files with 4154 additions and 4166 deletions

1
.gitignore vendored
View File

@ -59,3 +59,4 @@ bazel-telegram-ios/*
bazel-testlogs
bazel-testlogs/*
build-input/data/*
build-input/gen/*

View File

@ -5352,3 +5352,14 @@ Any member of this group will be able to see messages in the channel.";
"ChatList.EmptyChatListNewMessage" = "New Message";
"ChatList.EmptyChatListEditFilter" = "Edit Filter";
"Stats.Overview" = "OVERVIEW";
"Stats.Followers" = "Followers";
"Stats.EnabledNotifications" = "Enabled Notifications";
"Stats.ViewsPerPost" = "Views Per Post";
"Stats.SharesPerPost" = "Shares Per Post";
"Stats.GrowthTitle" = "GROWTH";
"Stats.FollowersTitle" = "FOLLOWERS";
"Stats.NotificationsTitle" = "NOTIFICATIONS";
"Stats.InteractionsTitle" = "INTERACTIONS";

View File

@ -19,7 +19,6 @@ class ChartStackSection: UIView, ColorModeContainer {
var sectionContainerView: UIView
var separators: [UIView] = []
var headerLabel: UILabel!
var titleLabel: UILabel!
var backButton: UIButton!
@ -30,7 +29,6 @@ class ChartStackSection: UIView, ColorModeContainer {
chartView = ChartView()
rangeView = RangeChartView()
visibilityView = ChartVisibilityView()
headerLabel = UILabel()
titleLabel = UILabel()
backButton = UIButton()
@ -40,9 +38,10 @@ class ChartStackSection: UIView, ColorModeContainer {
sectionContainerView.addSubview(chartView)
sectionContainerView.addSubview(rangeView)
sectionContainerView.addSubview(visibilityView)
sectionContainerView.addSubview(titleLabel)
headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular)
titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
titleLabel.textAlignment = .center
visibilityView.clipsToBounds = true
backButton.isExclusiveTouch = true
@ -56,7 +55,6 @@ class ChartStackSection: UIView, ColorModeContainer {
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
@ -95,7 +93,6 @@ class ChartStackSection: UIView, ColorModeContainer {
}
self.titleLabel.setTextColor(colorMode.chartTitleColor, animated: animated && titleLabel.isVisibleInWindow)
self.headerLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && headerLabel.isVisibleInWindow)
}
@IBAction func didTapBackButton() {
@ -130,6 +127,7 @@ class ChartStackSection: UIView, ColorModeContainer {
super.layoutSubviews()
let bounds = self.bounds
self.titleLabel.frame = CGRect(origin: CGPoint(x: 0.0, y: 10.0), size: CGSize(width: bounds.width, height: 48.0))
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))
@ -138,7 +136,6 @@ class ChartStackSection: UIView, ColorModeContainer {
func setup(controller: BaseChartController, title: String) {
self.controller = controller
self.headerLabel.text = title
// Chart
chartView.renderers = controller.mainChartRenderers
@ -195,5 +192,10 @@ class ChartStackSection: UIView, ColorModeContainer {
controller.initializeChart()
updateToolViews(animated: false)
TimeInterval.animationDurationMultipler = 0.0001
rangeView.setRange(0.75...1.0, animated: false)
controller.updateChartRange(0.75...1.0)
TimeInterval.animationDurationMultipler = 1.0
}
}

View File

@ -13,7 +13,7 @@ public protocol ChartViewRenderer: class {
func render(context: CGContext, bounds: CGRect, chartFrame: CGRect)
}
class ChartView: UIView {
class ChartView: UIControl {
override init(frame: CGRect) {
super.init(frame: frame)
@ -63,11 +63,18 @@ class ChartView: UIView {
var userDidSelectCoordinateClosure: ((CGPoint) -> Void)?
var userDidDeselectCoordinateClosure: (() -> Void)?
private var _isTracking: Bool = false
private var touchInitialLocation: CGPoint?
override var isTracking: Bool {
return self._isTracking
}
override func touchesBegan(_ touches: Set<UITouch>, 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)
self.touchInitialLocation = point
}
}
@ -76,15 +83,23 @@ class ChartView: UIView {
let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width,
y: (point.y - chartFrame.origin.y) / chartFrame.height)
userDidSelectCoordinateClosure?(fractionPoint)
if let initialPosition = self.touchInitialLocation, abs(initialPosition.x - point.x) > 3.0 {
self._isTracking = true
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
userDidDeselectCoordinateClosure?()
self.touchInitialLocation = nil
self._isTracking = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
userDidDeselectCoordinateClosure?()
self.touchInitialLocation = nil
self._isTracking = false
}
// MARK: Details View

View File

@ -1,222 +0,0 @@
//
// 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"
}
}
}

View File

@ -42,7 +42,8 @@ class RangeChartView: UIControl {
private let cropFrameView = UIImageView()
private var selectedMarker: Marker?
private var selectedMarkerHorizontalOffet: CGFloat = 0
private var selectedMarkerHorizontalOffset: CGFloat = 0
private var selectedMarkerInitialLocation: CGPoint?
private var isBoundCropHighlighted: Bool = false
private var isRangePagingEnabled: Bool = false
@ -137,18 +138,22 @@ class RangeChartView: UIControl {
if abs(locationInView(for: upperBound) - point.x + Constants.markerSelectionRange / 2) < Constants.markerSelectionRange {
selectedMarker = .upper
selectedMarkerHorizontalOffet = point.x - locationInView(for: upperBound)
selectedMarkerHorizontalOffset = point.x - locationInView(for: upperBound)
selectedMarkerInitialLocation = point
isBoundCropHighlighted = true
} else if abs(locationInView(for: lowerBound) - point.x - Constants.markerSelectionRange / 2) < Constants.markerSelectionRange {
selectedMarker = .lower
selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound)
selectedMarkerHorizontalOffset = point.x - locationInView(for: lowerBound)
selectedMarkerInitialLocation = point
isBoundCropHighlighted = true
} else if point.x > locationInView(for: lowerBound) && point.x < locationInView(for: upperBound) {
selectedMarker = .center
selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound)
selectedMarkerHorizontalOffset = point.x - locationInView(for: lowerBound)
selectedMarkerInitialLocation = point
isBoundCropHighlighted = true
} else {
selectedMarker = nil
selectedMarkerInitialLocation = nil
return
}
@ -160,10 +165,14 @@ class RangeChartView: UIControl {
guard let selectedMarker = selectedMarker else { return }
guard let point = touches.first?.location(in: self) else { return }
let horizontalPosition = point.x - selectedMarkerHorizontalOffet
let horizontalPosition = point.x - selectedMarkerHorizontalOffset
let fraction = fractionFor(offsetX: horizontalPosition)
updateMarkerOffset(selectedMarker, fraction: fraction)
if let initialPosition = selectedMarkerInitialLocation, abs(initialPosition.x - point.x) > 3.0 {
self._isTracking = true
}
sendActions(for: .valueChanged)
}
@ -175,11 +184,12 @@ class RangeChartView: UIControl {
}
guard let point = touches.first?.location(in: self) else { return }
let horizontalPosition = point.x - selectedMarkerHorizontalOffet
let horizontalPosition = point.x - selectedMarkerHorizontalOffset
let fraction = fractionFor(offsetX: horizontalPosition)
updateMarkerOffset(selectedMarker, fraction: fraction)
self.selectedMarker = nil
self.selectedMarkerInitialLocation = nil
self.isBoundCropHighlighted = false
if bounds.contains(point) {
sendActions(for: .touchUpInside)
@ -187,13 +197,22 @@ class RangeChartView: UIControl {
sendActions(for: .touchUpOutside)
}
rangeDidChangeClosure?(lowerBound...upperBound)
self._isTracking = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
self.selectedMarker = nil
self.selectedMarkerInitialLocation = nil
self.isBoundCropHighlighted = false
self._isTracking = false
sendActions(for: .touchCancel)
}
private var _isTracking: Bool = false
override var isTracking: Bool {
return self._isTracking
}
}
private extension RangeChartView {

View File

@ -23,12 +23,19 @@ public final class ChartNode: ASDisplayNode {
self.view.disablesInteractiveTransitionGestureRecognizer = true
}
@objc private func nop() {
}
public func setup(_ data: String, bar: Bool = false) {
var bar = bar
if data.contains("bar") {
bar = true
}
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)
controller = TwoAxisLinesChartController(chartsCollection: collection)
} else {
controller = GeneralLinesChartController(chartsCollection: collection)
}

View File

@ -76,7 +76,7 @@ extension ChartsCollection {
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)")
throw ChartsError.generalConversion("Sanitazing: Invalid number of items: \(axixValuesToSetup), \(chartToSetup)")
}
self.axisValues = axixValuesToSetup
self.chartValues = chartToSetup

View File

@ -74,7 +74,7 @@ class BaseChartController: ColorModeContainer {
init(chartsCollection: ChartsCollection) {
self.initialChartsCollection = chartsCollection
}
var mainChartRenderers: [ChartViewRenderer] {
fatalError("Abstract")
}
@ -128,7 +128,11 @@ class BaseChartController: ColorModeContainer {
fatalError("Abstract")
}
func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
func updateChartRangeTitle(animated: Bool) {
}
func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool = true) {
fatalError("Abstract")
}

View File

@ -25,9 +25,9 @@ class BaseLinesChartController: BaseChartController {
func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) {
if animated {
TimeInterval.setDefaultSuration(.expandAnimationDuration)
TimeInterval.setDefaultDuration(.expandAnimationDuration)
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
TimeInterval.setDefaultSuration(.osXDuration)
TimeInterval.setDefaultDuration(.osXDuration)
}
}
@ -39,7 +39,7 @@ class BaseLinesChartController: BaseChartController {
updateChartRangeTitle(animated: animated)
}
func updateChartRangeTitle(animated: Bool) {
override 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) {
@ -64,7 +64,7 @@ class BaseLinesChartController: BaseChartController {
isChartInteractionBegun = false
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
}

View File

@ -172,7 +172,7 @@ class GeneralLinesChartController: BaseLinesChartController {
return visibleCharts
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
cancelChartInteraction()
let horizontalRange = ClosedRange(uncheckedBounds:
@ -183,8 +183,8 @@ class GeneralLinesChartController: BaseLinesChartController {
updateChartRangeTitle(animated: true)
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
updateHorizontalLimists(horizontalRange: horizontalRange, animated: true)
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true)
updateHorizontalLimists(horizontalRange: horizontalRange, animated: animated)
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: animated)
}
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {

View File

@ -194,7 +194,7 @@ class TwoAxisLinesChartController: BaseLinesChartController {
self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false)
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
cancelChartInteraction()
let horizontalRange = ClosedRange(uncheckedBounds:
@ -205,8 +205,8 @@ class TwoAxisLinesChartController: BaseLinesChartController {
updateChartRangeTitle(animated: true)
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
updateHorizontalLimists(horizontalRange: horizontalRange, animated: true)
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true)
updateHorizontalLimists(horizontalRange: horizontalRange, animated: animated)
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: animated)
}
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {

View File

@ -93,9 +93,9 @@ class PercentPieChartController: BaseChartController {
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
if animated {
TimeInterval.setDefaultSuration(.expandAnimationDuration)
TimeInterval.setDefaultDuration(.expandAnimationDuration)
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
TimeInterval.setDefaultSuration(.osXDuration)
TimeInterval.setDefaultDuration(.osXDuration)
}
}
@ -263,7 +263,7 @@ class PercentPieChartController: BaseChartController {
})
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
if isZoomed {
return pieController.chartRangeFractionDidUpdated(rangeFraction)
} else {

View File

@ -84,9 +84,9 @@ class DailyBarsChartController: BaseChartController {
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
if animated {
TimeInterval.setDefaultSuration(.expandAnimationDuration)
TimeInterval.setDefaultDuration(.expandAnimationDuration)
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
TimeInterval.setDefaultSuration(.osXDuration)
TimeInterval.setDefaultDuration(.osXDuration)
}
}
@ -225,7 +225,7 @@ class DailyBarsChartController: BaseChartController {
switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true)
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
if isZoomed {
return linesController.chartRangeFractionDidUpdated(rangeFraction)
} else {

View File

@ -79,9 +79,9 @@ class StackedBarsChartController: BaseChartController {
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
if animated {
TimeInterval.setDefaultSuration(.expandAnimationDuration)
TimeInterval.setDefaultDuration(.expandAnimationDuration)
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
TimeInterval.setDefaultSuration(.osXDuration)
TimeInterval.setDefaultDuration(.osXDuration)
}
}
@ -226,7 +226,7 @@ class StackedBarsChartController: BaseChartController {
switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true)
}
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
if isZoomed {
return zoomedBarsController.chartRangeFractionDidUpdated(rangeFraction)
} else {

View File

@ -21,7 +21,7 @@ extension TimeInterval {
}
private static var innerDefaultDuration: TimeInterval = osXDuration
static func setDefaultSuration(_ duration: TimeInterval) {
static func setDefaultDuration(_ duration: TimeInterval) {
innerDefaultDuration = duration
}
}

View File

@ -652,6 +652,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
}
}
self.chatListDisplayNode.chatListNode.present = { [weak self] c in
if let strongSelf = self {
self?.present(c, in: .window(.root))
}
}
self.chatListDisplayNode.chatListNode.toggleArchivedFolderHiddenByDefault = { [weak self] in
guard let strongSelf = self else {
return

View File

@ -235,7 +235,9 @@ final class ChatListControllerNode: ASDisplayNode {
if let requestAddContact = self?.requestAddContact {
requestAddContact(phoneNumber)
}
}, peerContextAction: self.peerContextAction), cancel: { [weak self] in
}, peerContextAction: self.peerContextAction, present: { [weak self] c in
self?.controller?.present(c, in: .window(.root))
}), cancel: { [weak self] in
if let requestDeactivateSearch = self?.requestDeactivateSearch {
requestDeactivateSearch()
}

View File

@ -627,7 +627,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
private let filter: ChatListNodePeersFilter
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer originalOpenPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?) {
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer originalOpenPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage originalOpenMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController) -> Void) {
self.context = context
self.filter = filter
self.dimNode = ASDisplayNode()
@ -1043,6 +1043,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
case .groupReference:
gesture?.cancel()
}
}, present: { [weak self] c in
present(c)
})
self.interaction = interaction
@ -1390,8 +1392,24 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
private func clearRecentSearch() {
let _ = (clearRecentlySearchedPeers(postbox: self.context.account.postbox)
|> deliverOnMainQueue).start()
let presentationData = self.presentationData
let actionSheet = ActionSheetController(presentationData: presentationData)
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.WebSearch_RecentSectionClear, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
guard let strongSelf = self else {
return
}
let _ = (clearRecentlySearchedPeers(postbox: strongSelf.context.account.postbox)
|> deliverOnMainQueue).start()
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
self.interaction?.present(actionSheet)
}
override public func scrollToTop() {

View File

@ -61,11 +61,12 @@ public final class ChatListNodeInteraction {
let togglePeerMarkedUnread: (PeerId, Bool) -> Void
let toggleArchivedFolderHiddenByDefault: () -> Void
let activateChatPreview: (ChatListItem, ASDisplayNode, ContextGesture?) -> Void
let present: (ViewController) -> Void
public var searchTextHighightState: String?
var highlightedChatLocation: ChatListHighlightedLocation?
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, messageSelected: @escaping (Peer, Message, Bool) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void) {
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, messageSelected: @escaping (Peer, Message, Bool) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
self.activateSearch = activateSearch
self.peerSelected = peerSelected
self.disabledPeerSelected = disabledPeerSelected
@ -81,6 +82,7 @@ public final class ChatListNodeInteraction {
self.togglePeerMarkedUnread = togglePeerMarkedUnread
self.toggleArchivedFolderHiddenByDefault = toggleArchivedFolderHiddenByDefault
self.activateChatPreview = activateChatPreview
self.present = present
}
}
@ -358,6 +360,7 @@ public final class ChatListNode: ListView {
public var deletePeerChat: ((PeerId) -> Void)?
public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
public var presentAlert: ((String) -> Void)?
public var present: ((ViewController) -> Void)?
public var toggleArchivedFolderHiddenByDefault: (() -> Void)?
public var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)?
@ -562,6 +565,8 @@ public final class ChatListNode: ListView {
} else {
gesture?.cancel()
}
}, present: { [weak self] c in
self?.present?(c)
})
let viewProcessingQueue = self.viewProcessingQueue

View File

@ -354,8 +354,9 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
let trackingRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.trackingGesture(_:)))
trackingRecognizer.delegate = self
trackingRecognizer.cancelsTouchesInView = false
self.view.addGestureRecognizer(trackingRecognizer)
self.view.addGestureRecognizer(ListViewReorderingGestureRecognizer(shouldBegin: { [weak self] point in
if let strongSelf = self {
if let index = strongSelf.itemIndexAtPoint(point) {

View File

@ -28,6 +28,11 @@ public final class ListViewScroller: UIScrollView, UIGestureRecognizerDelegate {
return gestureRecognizer.numberOfTouches < 2
}
}
if let view = gestureRecognizer.view?.hitTest(gestureRecognizer.location(in: gestureRecognizer.view), with: nil) as? UIControl {
return !view.isTracking
}
return true
} else {
return true

View File

@ -71,6 +71,7 @@ public final class HashtagSearchController: TelegramBaseController {
}, toggleArchivedFolderHiddenByDefault: {
}, activateChatPreview: { _, _, gesture in
gesture?.cancel()
}, present: { _ in
})
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)

View File

@ -215,7 +215,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
gesture?.cancel()
})
}, present: { _ in })
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
let peers = SimpleDictionary<PeerId, Peer>()

View File

@ -768,6 +768,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
gesture?.cancel()
}, present: { _ in
})
let chatListPresentationData = ChatListPresentationData(theme: self.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)

View File

@ -352,6 +352,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
gesture?.cancel()
}, present: { _ in
})
let chatListPresentationData = ChatListPresentationData(theme: self.previewTheme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)

View File

@ -36,28 +36,28 @@ private enum StatsEntry: ItemListNodeEntry {
case overview(PresentationTheme, ChannelStats)
case growthTitle(PresentationTheme, String)
case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case followersTitle(PresentationTheme, String)
case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case notificationsTitle(PresentationTheme, String)
case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case viewsByHourTitle(PresentationTheme, String)
case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case postInteractionsTitle(PresentationTheme, String)
case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case viewsBySourceTitle(PresentationTheme, String)
case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case followersBySourceTitle(PresentationTheme, String)
case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
case languagesTitle(PresentationTheme, String)
case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
var section: ItemListSectionId {
switch self {
@ -143,8 +143,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .growthGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .growthGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -155,8 +155,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .followersGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .followersGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -167,8 +167,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .notificationsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .notificationsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -179,8 +179,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .viewsByHourGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .viewsByHourGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -191,8 +191,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .postInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .postInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -203,8 +203,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .viewsBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .viewsBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -215,8 +215,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .followersBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .followersBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -227,8 +227,8 @@ private enum StatsEntry: ItemListNodeEntry {
} 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 {
case let .languagesGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
if case let .languagesGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
return true
} else {
return false
@ -254,15 +254,15 @@ private enum StatsEntry: ItemListNodeEntry {
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)
case let .growthGraph(theme, strings, dateTimeFormat, graph),
let .followersGraph(theme, strings, dateTimeFormat, graph),
let .notificationsGraph(theme, strings, dateTimeFormat, graph),
let .viewsByHourGraph(theme, strings, dateTimeFormat, graph),
let .postInteractionsGraph(theme, strings, dateTimeFormat, graph),
let .viewsBySourceGraph(theme, strings, dateTimeFormat, graph),
let .followersBySourceGraph(theme, strings, dateTimeFormat, graph),
let .languagesGraph(theme, strings, dateTimeFormat, graph):
return StatsGraphItem(presentationData: presentationData, graph: graph, sectionId: self.section, style: .blocks)
}
}
}
@ -271,17 +271,20 @@ private func statsControllerEntries(data: ChannelStats?, presentationData: Prese
var entries: [StatsEntry] = []
if let data = data {
entries.append(.overviewHeader(presentationData.theme, "OVERVIEW"))
entries.append(.overviewHeader(presentationData.theme, presentationData.strings.Stats_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(.growthTitle(presentationData.theme, presentationData.strings.Stats_GrowthTitle))
entries.append(.growthGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.growthGraph))
entries.append(.followersTitle(presentationData.theme, "FOLLOWERS"))
entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Followers", data.followersGraph))
entries.append(.followersTitle(presentationData.theme, presentationData.strings.Stats_FollowersTitle))
entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.followersGraph))
entries.append(.notificationsTitle(presentationData.theme, "NOTIFICATIONS"))
entries.append(.notificationsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Notifications", data.muteGraph))
entries.append(.notificationsTitle(presentationData.theme, presentationData.strings.Stats_NotificationsTitle))
entries.append(.notificationsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.muteGraph))
entries.append(.postInteractionsTitle(presentationData.theme, presentationData.strings.Stats_InteractionsTitle))
entries.append(.postInteractionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.interactionsGraph))
}
return entries
@ -321,8 +324,13 @@ public func channelStatsController(context: AccountContext, peer: Peer, cachedPe
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get())
|> deliverOnMainQueue
|> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState, Any)) in
var emptyStateItem: ItemListControllerEmptyStateItem?
if data == nil {
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
}
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)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: statsControllerEntries(data: data, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: false, animateChanges: false)
return (controllerState, (listState, arguments))
}
@ -345,5 +353,6 @@ public func channelStatsController(context: AccountContext, peer: Peer, cachedPe
controller.present(c, in: .window(.root), with: a)
}
}
return controller
}

View File

@ -12,14 +12,12 @@ 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) {
init(presentationData: ItemListPresentationData, graph: ChannelStatsGraph, sectionId: ItemListSectionId, style: ItemListStyle) {
self.presentationData = presentationData
self.title = title
self.graph = graph
self.sectionId = sectionId
self.style = style
@ -117,12 +115,12 @@ class StatsGraphItemNode: ListViewItemNode {
case .plain:
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor
contentSize = CGSize(width: params.width, height: 320.0)
contentSize = CGSize(width: params.width, height: 340.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)
contentSize = CGSize(width: params.width, height: 340.0)
insets = itemListNeighborsGroupedInsets(neighbors)
}
@ -137,11 +135,7 @@ class StatsGraphItemNode: ListViewItemNode {
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 {
@ -179,12 +173,17 @@ class StatsGraphItemNode: ListViewItemNode {
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.chartNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -10.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))
}
if let updatedGraph = updatedGraph, case let .Loaded(data) = updatedGraph {
var data = data.replacingOccurrences(of: "step", with: "bar")
strongSelf.chartNode.setup(data)
}
}
})
}

View File

@ -151,32 +151,60 @@ class StatsOverviewItemNode: ListViewItemNode {
updatedTheme = item.presentationData.theme
}
let valueFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize)
let valueFont = Font.semibold(item.presentationData.fontSize.itemListBaseFontSize)
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 (followersValueLabelLayout, followersValueLabelApply) = makeFollowersValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: compactNumericCountString(Int(item.stats.followers.current)), font: valueFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (viewsPerPostValueLabelLayout, viewsPerPostValueLabelApply) = makeViewsPerPostValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: compactNumericCountString(Int(item.stats.viewsPerPost.current)), font: valueFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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: compactNumericCountString(Int(item.stats.sharesPerPost.current)), font: valueFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), 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()))
var enabledNotifications: Double = 0.0
if item.stats.enabledNotifications.total > 0 {
enabledNotifications = item.stats.enabledNotifications.value / item.stats.enabledNotifications.total
}
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 (enabledNotificationsValueLabelLayout, enabledNotificationsValueLabelApply) = makeEnabledNotificationsValueLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: String(format: "%.02f%%", enabledNotifications * 100.0), font: valueFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), 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: item.presentationData.strings.Stats_Followers, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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: item.presentationData.strings.Stats_ViewsPerPost, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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: item.presentationData.strings.Stats_SharesPerPost, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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: item.presentationData.strings.Stats_EnabledNotifications, font: titleFont, textColor: item.presentationData.theme.list.sectionHeaderTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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 followersDeltaValue = item.stats.followers.current - item.stats.followers.previous
let followersDeltaCompact = compactNumericCountString(abs(Int(followersDeltaValue)))
let followersDelta = followersDeltaValue > 0 ? "+\(followersDeltaCompact)" : "-\(followersDeltaCompact)"
var followersDeltaPercentage = 0.0
if item.stats.followers.previous > 0.0 {
followersDeltaPercentage = abs(followersDeltaValue / item.stats.followers.previous)
}
let (followersDeltaLabelLayout, followersDeltaLabelApply) = makeFollowersDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: String(format: "%@ (%.02f%%)", followersDelta, followersDeltaPercentage * 100.0), font: deltaFont, textColor: followersDeltaValue > 0.0 ? item.presentationData.theme.list.freeTextSuccessColor : item.presentationData.theme.list.freeTextErrorColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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 viewsPerPostDeltaValue = item.stats.viewsPerPost.current - item.stats.viewsPerPost.previous
let viewsPerPostDeltaCompact = compactNumericCountString(abs(Int(viewsPerPostDeltaValue)))
let viewsPerPostDelta = viewsPerPostDeltaValue > 0 ? "+\(viewsPerPostDeltaCompact)" : "-\(viewsPerPostDeltaCompact)"
var viewsPerPostDeltaPercentage = 0.0
if item.stats.viewsPerPost.previous > 0.0 {
viewsPerPostDeltaPercentage = abs(viewsPerPostDeltaValue / item.stats.viewsPerPost.previous)
}
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 (viewsPerPostDeltaLabelLayout, viewsPerPostDeltaLabelApply) = makeViewsPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: String(format: "%@ (%.02f%%)", viewsPerPostDelta, viewsPerPostDeltaPercentage * 100.0), font: deltaFont, textColor: viewsPerPostDeltaValue > 0.0 ? item.presentationData.theme.list.freeTextSuccessColor : item.presentationData.theme.list.freeTextErrorColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.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 sharesPerPostDeltaValue = item.stats.sharesPerPost.current - item.stats.sharesPerPost.previous
let sharesPerPostDeltaCompact = compactNumericCountString(abs(Int(sharesPerPostDeltaValue)))
let sharesPerPostDelta = sharesPerPostDeltaValue > 0 ? "+\(sharesPerPostDeltaCompact)" : "-\(sharesPerPostDeltaCompact)"
var sharesPerPostDeltaPercentage = 0.0
if item.stats.sharesPerPost.previous > 0.0 {
sharesPerPostDeltaPercentage = abs(sharesPerPostDeltaValue / item.stats.sharesPerPost.previous)
}
let (sharesPerPostDeltaLabelLayout, sharesPerPostDeltaLabelApply) = makeSharesPerPostDeltaLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: String(format: "%@ (%.02f%%)", sharesPerPostDelta, sharesPerPostDeltaPercentage * 100.0), font: deltaFont, textColor: sharesPerPostDeltaValue > 0.0 ? item.presentationData.theme.list.freeTextSuccessColor : item.presentationData.theme.list.freeTextErrorColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 140.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let contentSize: CGSize
let insets: UIEdgeInsets
@ -265,13 +293,28 @@ class StatsOverviewItemNode: ListViewItemNode {
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)
let horizontalSpacing: CGFloat = 4.0
let verticalSpacing: CGFloat = 70.0
let topInset: CGFloat = 14.0
let sideInset: CGFloat = 16.0
strongSelf.viewsPerPostValueLabel.frame = CGRect(origin: CGPoint(x: leftInset, y: 44.0), size: viewsPerPostValueLabelLayout.size)
strongSelf.followersValueLabel.frame = CGRect(origin: CGPoint(x: sideInset + leftInset, y: topInset), size: followersValueLabelLayout.size)
strongSelf.followersTitleLabel.frame = CGRect(origin: CGPoint(x: sideInset + leftInset, y: strongSelf.followersValueLabel.frame.maxY), size: followersTitleLabelLayout.size)
strongSelf.followersDeltaLabel.frame = CGRect(origin: CGPoint(x: strongSelf.followersValueLabel.frame.maxX + horizontalSpacing, y: strongSelf.followersValueLabel.frame.minY + 4.0), size: followersDeltaLabelLayout.size)
strongSelf.sharesPerPostValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 44.0), size: sharesPerPostValueLabelLayout.size)
strongSelf.viewsPerPostValueLabel.frame = CGRect(origin: CGPoint(x: sideInset + leftInset, y: verticalSpacing), size: viewsPerPostValueLabelLayout.size)
strongSelf.viewsPerPostTitleLabel.frame = CGRect(origin: CGPoint(x: sideInset + leftInset, y: strongSelf.viewsPerPostValueLabel.frame.maxY), size: viewsPerPostTitleLabelLayout.size)
strongSelf.viewsPerPostDeltaLabel.frame = CGRect(origin: CGPoint(x: strongSelf.viewsPerPostValueLabel.frame.maxX + horizontalSpacing, y: strongSelf.viewsPerPostValueLabel.frame.minY + 4.0), size: viewsPerPostDeltaLabelLayout.size)
strongSelf.enabledNotificationsValueLabel.frame = CGRect(origin: CGPoint(x: layout.size.width / 2.0, y: 7.0), size: enabledNotificationsValueLabelLayout.size)
let rightColumnX = max(layout.size.width / 2.0, max(strongSelf.followersDeltaLabel.frame.maxX, strongSelf.viewsPerPostDeltaLabel.frame.maxX) + horizontalSpacing)
strongSelf.sharesPerPostValueLabel.frame = CGRect(origin: CGPoint(x: rightColumnX, y: verticalSpacing), size: sharesPerPostValueLabelLayout.size)
strongSelf.enabledNotificationsValueLabel.frame = CGRect(origin: CGPoint(x: rightColumnX, y: topInset), size: enabledNotificationsValueLabelLayout.size)
strongSelf.sharesPerPostTitleLabel.frame = CGRect(origin: CGPoint(x: rightColumnX, y: strongSelf.sharesPerPostValueLabel.frame.maxY), size: sharesPerPostTitleLabelLayout.size)
strongSelf.enabledNotificationsTitleLabel.frame = CGRect(origin: CGPoint(x: rightColumnX, y: strongSelf.enabledNotificationsValueLabel.frame.maxY), size: enabledNotificationsTitleLabelLayout.size)
strongSelf.sharesPerPostDeltaLabel.frame = CGRect(origin: CGPoint(x: strongSelf.sharesPerPostValueLabel.frame.maxX + horizontalSpacing, y: strongSelf.sharesPerPostValueLabel.frame.minY + 4.0), size: sharesPerPostDeltaLabelLayout.size)
}
})
}

View File

@ -418,7 +418,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
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[-1901828938] = { 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) }
@ -529,7 +529,8 @@ 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[-1387279939] = { return Api.MessageInteractionCounters.parse_messageInteractionCounters($0) }
dict[821185690] = { 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) }
@ -775,7 +776,6 @@ 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) }
@ -1225,6 +1225,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.PaymentCharge:
_1.serialize(buffer, boxed)
case let _1 as Api.MessageInteractionCounters:
_1.serialize(buffer, boxed)
case let _1 as Api.stats.BroadcastStats:
_1.serialize(buffer, boxed)
case let _1 as Api.Updates:
@ -1413,8 +1415,6 @@ 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:

View File

@ -12044,7 +12044,7 @@ public extension Api {
public enum StatsGraph: TypeConstructorDescription {
case statsGraphAsync(token: String)
case statsGraphError(error: String)
case statsGraph(json: Api.DataJSON)
case statsGraph(flags: Int32, json: Api.DataJSON, zoomToken: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -12060,11 +12060,13 @@ public extension Api {
}
serializeString(error, buffer: buffer, boxed: false)
break
case .statsGraph(let json):
case .statsGraph(let flags, let json, let zoomToken):
if boxed {
buffer.appendInt32(-1057809608)
buffer.appendInt32(-1901828938)
}
serializeInt32(flags, buffer: buffer, boxed: false)
json.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(zoomToken!, buffer: buffer, boxed: false)}
break
}
}
@ -12075,8 +12077,8 @@ public extension Api {
return ("statsGraphAsync", [("token", token)])
case .statsGraphError(let error):
return ("statsGraphError", [("error", error)])
case .statsGraph(let json):
return ("statsGraph", [("json", json)])
case .statsGraph(let flags, let json, let zoomToken):
return ("statsGraph", [("flags", flags), ("json", json), ("zoomToken", zoomToken)])
}
}
@ -12103,13 +12105,19 @@ public extension Api {
}
}
public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? {
var _1: Api.DataJSON?
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.DataJSON?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.DataJSON
_2 = Api.parse(reader, signature: signature) as? Api.DataJSON
}
var _3: String?
if Int(_1!) & Int(1 << 0) != 0 {_3 = parseString(reader) }
let _c1 = _1 != nil
if _c1 {
return Api.StatsGraph.statsGraph(json: _1!)
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.StatsGraph.statsGraph(flags: _1!, json: _2!, zoomToken: _3)
}
else {
return nil
@ -14978,6 +14986,48 @@ public extension Api {
}
}
}
public enum MessageInteractionCounters: TypeConstructorDescription {
case messageInteractionCounters(msgId: Int32, views: Int32, forwards: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageInteractionCounters(let msgId, let views, let forwards):
if boxed {
buffer.appendInt32(-1387279939)
}
serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(views, buffer: buffer, boxed: false)
serializeInt32(forwards, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageInteractionCounters(let msgId, let views, let forwards):
return ("messageInteractionCounters", [("msgId", msgId), ("views", views), ("forwards", forwards)])
}
}
public static func parse_messageInteractionCounters(_ reader: BufferReader) -> MessageInteractionCounters? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MessageInteractionCounters.messageInteractionCounters(msgId: _1!, views: _2!, forwards: _3!)
}
else {
return nil
}
}
}
public enum Updates: TypeConstructorDescription {
case updatesTooLong
@ -21264,54 +21314,6 @@ 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)

View File

@ -539,47 +539,40 @@ public struct payments {
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)
case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters])
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):
case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions):
if boxed {
buffer.appendInt32(205195937)
buffer.appendInt32(821185690)
}
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)
viewsBySourceGraph.serialize(buffer, true)
newFollowersBySourceGraph.serialize(buffer, true)
languagesGraph.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentMessageInteractions.count))
for item in recentMessageInteractions {
item.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)])
case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions):
return ("broadcastStats", [("period", period), ("followers", followers), ("viewsPerPost", viewsPerPost), ("sharesPerPost", sharesPerPost), ("enabledNotifications", enabledNotifications), ("growthGraph", growthGraph), ("followersGraph", followersGraph), ("muteGraph", muteGraph), ("topHoursGraph", topHoursGraph), ("interactionsGraph", interactionsGraph), ("viewsBySourceGraph", viewsBySourceGraph), ("newFollowersBySourceGraph", newFollowersBySourceGraph), ("languagesGraph", languagesGraph), ("recentMessageInteractions", recentMessageInteractions)])
}
}
@ -604,17 +597,17 @@ public struct stats {
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 _6: Api.StatsGraph?
if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _7: [Api.StatsRowAbsValueAndPrev]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self)
var _7: Api.StatsGraph?
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _8: [Api.StatsRowAbsValueAndPrev]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self)
var _8: Api.StatsGraph?
if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _9: Api.StatsGraph?
if let signature = reader.readInt32() {
@ -636,6 +629,10 @@ public struct stats {
if let signature = reader.readInt32() {
_13 = Api.parse(reader, signature: signature) as? Api.StatsGraph
}
var _14: [Api.MessageInteractionCounters]?
if let _ = reader.readInt32() {
_14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageInteractionCounters.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -649,8 +646,9 @@ public struct stats {
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!)
let _c14 = _14 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, growthGraph: _6!, followersGraph: _7!, muteGraph: _8!, topHoursGraph: _9!, interactionsGraph: _10!, viewsBySourceGraph: _11!, newFollowersBySourceGraph: _12!, languagesGraph: _13!, recentMessageInteractions: _14!)
}
else {
return nil

View File

@ -3964,11 +3964,13 @@ public extension Api {
})
}
public static func loadAsyncGraph(token: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.StatsGraph>) {
public static func loadAsyncGraph(flags: Int32, token: String, x: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.StatsGraph>) {
let buffer = Buffer()
buffer.appendInt32(1749505346)
buffer.appendInt32(1646092192)
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(token, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("token", token)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(x!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "stats.loadAsyncGraph", parameters: [("flags", flags), ("token", token), ("x", x)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StatsGraph? in
let reader = BufferReader(buffer)
var result: Api.StatsGraph?
if let signature = reader.readInt32() {

View File

@ -16,7 +16,7 @@ public struct ChannelStatsValue: Equatable {
}
public struct ChannelStatsPercentValue: Equatable {
public let fraction: Double
public let value: Double
public let total: Double
}
@ -422,7 +422,7 @@ extension ChannelStatsPercentValue {
init(apiPercentValue: Api.StatsPercentValue) {
switch apiPercentValue {
case let .statsPercentValue(part, total):
self = ChannelStatsPercentValue(fraction: part, total: total)
self = ChannelStatsPercentValue(value: part, total: total)
}
}
}
@ -435,4 +435,3 @@ extension ChannelStats {
}
}
}

View File

@ -202,6 +202,7 @@ framework(
"//submodules/SemanticStatusNode:SemanticStatusNode",
"//submodules/AccountUtils:AccountUtils",
"//submodules/Svg:Svg",
"//submodules/StatisticsUI:StatisticsUI",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -1362,32 +1362,61 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
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))
for url in info.urls {
items.append(ActionSheetButtonItem(title: url.title, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.controllerInteraction?.openUrl(url.url, false, false, message)
}
}))
}
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = number
}))
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))
}
})
// var signal = getBankCardInfo(account: strongSelf.context.account, cardNumber: number)
//
// var cancelImpl: (() -> Void)?
// let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
// let progressSignal = Signal<Never, NoError> { subscriber in
// let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
// cancelImpl?()
// }))
// strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
// return ActionDisposable { [weak controller] in
// Queue.mainQueue().async() {
// controller?.dismiss()
// }
// }
// }
// |> runOn(Queue.mainQueue())
// |> delay(0.15, queue: Queue.mainQueue())
// let progressDisposable = progressSignal.start()
//
// signal = signal
// |> afterDisposed {
// Queue.mainQueue().async {
// progressDisposable.dispose()
// }
// }
// cancelImpl = {
// disposable.set(nil)
// }
// disposable.set((signal
// |> 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))
// for url in info.urls {
// items.append(ActionSheetButtonItem(title: url.title, color: .accent, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// if let strongSelf = self {
// strongSelf.controllerInteraction?.openUrl(url.url, false, false, message)
// }
// }))
// }
// items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// UIPasteboard.general.string = number
// }))
// 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()
}
}

View File

@ -204,6 +204,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
default:
gesture?.cancel()
}
}, present: { _ in
})
interaction.searchTextHighightState = searchQuery
self.interaction = interaction

View File

@ -1,6 +1,7 @@
import Foundation
import UIKit
import Display
import SyncCore
import AsyncDisplayKit
import TelegramPresentationData
import TelegramUIPreferences

View File

@ -36,6 +36,7 @@ import LocationResources
import LocationUI
import Geocoding
import TextFormat
import StatisticsUI
protocol PeerInfoScreenItem: class {
var id: AnyHashable { get }
@ -2215,6 +2216,13 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
}
} else if let channel = peer as? TelegramChannel {
if let cachedData = self.data?.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) {
items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_Stats, color: .accent, action: { [weak self] in
dismissAction()
self?.openStats()
}))
}
var canReport = true
if channel.isVerified {
canReport = false
@ -2691,6 +2699,15 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
})
}
private func openStats() {
guard let controller = self.controller, let data = self.data, let peer = data.peer, let cachedData = data.cachedData else {
return
}
self.view.endEditing(true)
controller.push(channelStatsController(context: self.context, peer: peer, cachedPeerData: cachedData))
}
private func openReport(user: Bool) {
guard let controller = self.controller else {
return

View File

@ -223,7 +223,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
if let requestOpenMessageFromSearch = self?.requestOpenMessageFromSearch {
requestOpenMessageFromSearch(peer, messageId)
}
}, addContact: nil, peerContextAction: nil), cancel: { [weak self] in
}, addContact: nil, peerContextAction: nil, present: { _ in
}), cancel: { [weak self] in
if let requestDeactivateSearch = self?.requestDeactivateSearch {
requestDeactivateSearch()
}