mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
# Conflicts: # submodules/TelegramCore/Sources/ChannelStatistics.swift
This commit is contained in:
commit
e38a69235d
1
.gitignore
vendored
1
.gitignore
vendored
@ -59,3 +59,4 @@ bazel-telegram-ios/*
|
|||||||
bazel-testlogs
|
bazel-testlogs
|
||||||
bazel-testlogs/*
|
bazel-testlogs/*
|
||||||
build-input/data/*
|
build-input/data/*
|
||||||
|
build-input/gen/*
|
||||||
|
@ -5352,3 +5352,14 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
|
|
||||||
"ChatList.EmptyChatListNewMessage" = "New Message";
|
"ChatList.EmptyChatListNewMessage" = "New Message";
|
||||||
"ChatList.EmptyChatListEditFilter" = "Edit Filter";
|
"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";
|
||||||
|
@ -19,7 +19,6 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
var sectionContainerView: UIView
|
var sectionContainerView: UIView
|
||||||
var separators: [UIView] = []
|
var separators: [UIView] = []
|
||||||
|
|
||||||
var headerLabel: UILabel!
|
|
||||||
var titleLabel: UILabel!
|
var titleLabel: UILabel!
|
||||||
var backButton: UIButton!
|
var backButton: UIButton!
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
chartView = ChartView()
|
chartView = ChartView()
|
||||||
rangeView = RangeChartView()
|
rangeView = RangeChartView()
|
||||||
visibilityView = ChartVisibilityView()
|
visibilityView = ChartVisibilityView()
|
||||||
headerLabel = UILabel()
|
|
||||||
titleLabel = UILabel()
|
titleLabel = UILabel()
|
||||||
backButton = UIButton()
|
backButton = UIButton()
|
||||||
|
|
||||||
@ -40,9 +38,10 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
sectionContainerView.addSubview(chartView)
|
sectionContainerView.addSubview(chartView)
|
||||||
sectionContainerView.addSubview(rangeView)
|
sectionContainerView.addSubview(rangeView)
|
||||||
sectionContainerView.addSubview(visibilityView)
|
sectionContainerView.addSubview(visibilityView)
|
||||||
|
sectionContainerView.addSubview(titleLabel)
|
||||||
|
|
||||||
headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular)
|
|
||||||
titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
|
titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
|
||||||
|
titleLabel.textAlignment = .center
|
||||||
visibilityView.clipsToBounds = true
|
visibilityView.clipsToBounds = true
|
||||||
backButton.isExclusiveTouch = true
|
backButton.isExclusiveTouch = true
|
||||||
|
|
||||||
@ -56,7 +55,6 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
|
|
||||||
headerLabel.font = UIFont.systemFont(ofSize: 14, weight: .regular)
|
|
||||||
titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
|
titleLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold)
|
||||||
visibilityView.clipsToBounds = true
|
visibilityView.clipsToBounds = true
|
||||||
backButton.isExclusiveTouch = true
|
backButton.isExclusiveTouch = true
|
||||||
@ -95,7 +93,6 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.titleLabel.setTextColor(colorMode.chartTitleColor, animated: animated && titleLabel.isVisibleInWindow)
|
self.titleLabel.setTextColor(colorMode.chartTitleColor, animated: animated && titleLabel.isVisibleInWindow)
|
||||||
self.headerLabel.setTextColor(colorMode.sectionTitleColor, animated: animated && headerLabel.isVisibleInWindow)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func didTapBackButton() {
|
@IBAction func didTapBackButton() {
|
||||||
@ -130,6 +127,7 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
let bounds = self.bounds
|
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.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.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.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) {
|
func setup(controller: BaseChartController, title: String) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.headerLabel.text = title
|
|
||||||
|
|
||||||
// Chart
|
// Chart
|
||||||
chartView.renderers = controller.mainChartRenderers
|
chartView.renderers = controller.mainChartRenderers
|
||||||
@ -195,5 +192,10 @@ class ChartStackSection: UIView, ColorModeContainer {
|
|||||||
|
|
||||||
controller.initializeChart()
|
controller.initializeChart()
|
||||||
updateToolViews(animated: false)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public protocol ChartViewRenderer: class {
|
|||||||
func render(context: CGContext, bounds: CGRect, chartFrame: CGRect)
|
func render(context: CGContext, bounds: CGRect, chartFrame: CGRect)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChartView: UIView {
|
class ChartView: UIControl {
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
|
|
||||||
@ -63,11 +63,18 @@ class ChartView: UIView {
|
|||||||
var userDidSelectCoordinateClosure: ((CGPoint) -> Void)?
|
var userDidSelectCoordinateClosure: ((CGPoint) -> Void)?
|
||||||
var userDidDeselectCoordinateClosure: (() -> 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?) {
|
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
if let point = touches.first?.location(in: self) {
|
if let point = touches.first?.location(in: self) {
|
||||||
let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width,
|
let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width,
|
||||||
y: (point.y - chartFrame.origin.y) / chartFrame.height)
|
y: (point.y - chartFrame.origin.y) / chartFrame.height)
|
||||||
userDidSelectCoordinateClosure?(fractionPoint)
|
userDidSelectCoordinateClosure?(fractionPoint)
|
||||||
|
self.touchInitialLocation = point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,15 +83,23 @@ class ChartView: UIView {
|
|||||||
let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width,
|
let fractionPoint = CGPoint(x: (point.x - chartFrame.origin.x) / chartFrame.width,
|
||||||
y: (point.y - chartFrame.origin.y) / chartFrame.height)
|
y: (point.y - chartFrame.origin.y) / chartFrame.height)
|
||||||
userDidSelectCoordinateClosure?(fractionPoint)
|
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?) {
|
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
userDidDeselectCoordinateClosure?()
|
userDidDeselectCoordinateClosure?()
|
||||||
|
self.touchInitialLocation = nil
|
||||||
|
self._isTracking = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
userDidDeselectCoordinateClosure?()
|
userDidDeselectCoordinateClosure?()
|
||||||
|
self.touchInitialLocation = nil
|
||||||
|
self._isTracking = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Details View
|
// MARK: Details View
|
||||||
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -42,7 +42,8 @@ class RangeChartView: UIControl {
|
|||||||
private let cropFrameView = UIImageView()
|
private let cropFrameView = UIImageView()
|
||||||
|
|
||||||
private var selectedMarker: Marker?
|
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 isBoundCropHighlighted: Bool = false
|
||||||
private var isRangePagingEnabled: 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 {
|
if abs(locationInView(for: upperBound) - point.x + Constants.markerSelectionRange / 2) < Constants.markerSelectionRange {
|
||||||
selectedMarker = .upper
|
selectedMarker = .upper
|
||||||
selectedMarkerHorizontalOffet = point.x - locationInView(for: upperBound)
|
selectedMarkerHorizontalOffset = point.x - locationInView(for: upperBound)
|
||||||
|
selectedMarkerInitialLocation = point
|
||||||
isBoundCropHighlighted = true
|
isBoundCropHighlighted = true
|
||||||
} else if abs(locationInView(for: lowerBound) - point.x - Constants.markerSelectionRange / 2) < Constants.markerSelectionRange {
|
} else if abs(locationInView(for: lowerBound) - point.x - Constants.markerSelectionRange / 2) < Constants.markerSelectionRange {
|
||||||
selectedMarker = .lower
|
selectedMarker = .lower
|
||||||
selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound)
|
selectedMarkerHorizontalOffset = point.x - locationInView(for: lowerBound)
|
||||||
|
selectedMarkerInitialLocation = point
|
||||||
isBoundCropHighlighted = true
|
isBoundCropHighlighted = true
|
||||||
} else if point.x > locationInView(for: lowerBound) && point.x < locationInView(for: upperBound) {
|
} else if point.x > locationInView(for: lowerBound) && point.x < locationInView(for: upperBound) {
|
||||||
selectedMarker = .center
|
selectedMarker = .center
|
||||||
selectedMarkerHorizontalOffet = point.x - locationInView(for: lowerBound)
|
selectedMarkerHorizontalOffset = point.x - locationInView(for: lowerBound)
|
||||||
|
selectedMarkerInitialLocation = point
|
||||||
isBoundCropHighlighted = true
|
isBoundCropHighlighted = true
|
||||||
} else {
|
} else {
|
||||||
selectedMarker = nil
|
selectedMarker = nil
|
||||||
|
selectedMarkerInitialLocation = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,10 +165,14 @@ class RangeChartView: UIControl {
|
|||||||
guard let selectedMarker = selectedMarker else { return }
|
guard let selectedMarker = selectedMarker else { return }
|
||||||
guard let point = touches.first?.location(in: self) 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)
|
let fraction = fractionFor(offsetX: horizontalPosition)
|
||||||
updateMarkerOffset(selectedMarker, fraction: fraction)
|
updateMarkerOffset(selectedMarker, fraction: fraction)
|
||||||
|
|
||||||
|
if let initialPosition = selectedMarkerInitialLocation, abs(initialPosition.x - point.x) > 3.0 {
|
||||||
|
self._isTracking = true
|
||||||
|
}
|
||||||
|
|
||||||
sendActions(for: .valueChanged)
|
sendActions(for: .valueChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,11 +184,12 @@ class RangeChartView: UIControl {
|
|||||||
}
|
}
|
||||||
guard let point = touches.first?.location(in: self) 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)
|
let fraction = fractionFor(offsetX: horizontalPosition)
|
||||||
updateMarkerOffset(selectedMarker, fraction: fraction)
|
updateMarkerOffset(selectedMarker, fraction: fraction)
|
||||||
|
|
||||||
self.selectedMarker = nil
|
self.selectedMarker = nil
|
||||||
|
self.selectedMarkerInitialLocation = nil
|
||||||
self.isBoundCropHighlighted = false
|
self.isBoundCropHighlighted = false
|
||||||
if bounds.contains(point) {
|
if bounds.contains(point) {
|
||||||
sendActions(for: .touchUpInside)
|
sendActions(for: .touchUpInside)
|
||||||
@ -187,13 +197,22 @@ class RangeChartView: UIControl {
|
|||||||
sendActions(for: .touchUpOutside)
|
sendActions(for: .touchUpOutside)
|
||||||
}
|
}
|
||||||
rangeDidChangeClosure?(lowerBound...upperBound)
|
rangeDidChangeClosure?(lowerBound...upperBound)
|
||||||
|
|
||||||
|
self._isTracking = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||||
self.selectedMarker = nil
|
self.selectedMarker = nil
|
||||||
|
self.selectedMarkerInitialLocation = nil
|
||||||
self.isBoundCropHighlighted = false
|
self.isBoundCropHighlighted = false
|
||||||
|
self._isTracking = false
|
||||||
sendActions(for: .touchCancel)
|
sendActions(for: .touchCancel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var _isTracking: Bool = false
|
||||||
|
override var isTracking: Bool {
|
||||||
|
return self._isTracking
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension RangeChartView {
|
private extension RangeChartView {
|
||||||
|
@ -23,12 +23,19 @@ public final class ChartNode: ASDisplayNode {
|
|||||||
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func nop() {
|
||||||
|
}
|
||||||
|
|
||||||
public func setup(_ data: String, bar: Bool = false) {
|
public func setup(_ data: String, bar: Bool = false) {
|
||||||
|
var bar = bar
|
||||||
|
if data.contains("bar") {
|
||||||
|
bar = true
|
||||||
|
}
|
||||||
if let data = data.data(using: .utf8) {
|
if let data = data.data(using: .utf8) {
|
||||||
ChartsDataManager().readChart(data: data, extraCopiesCount: 0, sync: true, success: { [weak self] collection in
|
ChartsDataManager().readChart(data: data, extraCopiesCount: 0, sync: true, success: { [weak self] collection in
|
||||||
let controller: BaseChartController
|
let controller: BaseChartController
|
||||||
if bar {
|
if bar {
|
||||||
controller = DailyBarsChartController(chartsCollection: collection)
|
controller = TwoAxisLinesChartController(chartsCollection: collection)
|
||||||
} else {
|
} else {
|
||||||
controller = GeneralLinesChartController(chartsCollection: collection)
|
controller = GeneralLinesChartController(chartsCollection: collection)
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ extension ChartsCollection {
|
|||||||
guard axixValuesToSetup.isEmpty == false,
|
guard axixValuesToSetup.isEmpty == false,
|
||||||
chartToSetup.isEmpty == false,
|
chartToSetup.isEmpty == false,
|
||||||
chartToSetup.firstIndex(where: { $0.values.count != axixValuesToSetup.count }) == nil else {
|
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.axisValues = axixValuesToSetup
|
||||||
self.chartValues = chartToSetup
|
self.chartValues = chartToSetup
|
||||||
|
@ -128,7 +128,11 @@ class BaseChartController: ColorModeContainer {
|
|||||||
fatalError("Abstract")
|
fatalError("Abstract")
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
func updateChartRangeTitle(animated: Bool) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool = true) {
|
||||||
fatalError("Abstract")
|
fatalError("Abstract")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ class BaseLinesChartController: BaseChartController {
|
|||||||
|
|
||||||
func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) {
|
func setupChartCollection(chartsCollection: ChartsCollection, animated: Bool, isZoomed: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
TimeInterval.setDefaultSuration(.expandAnimationDuration)
|
TimeInterval.setDefaultDuration(.expandAnimationDuration)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + .expandAnimationDuration) {
|
||||||
TimeInterval.setDefaultSuration(.osXDuration)
|
TimeInterval.setDefaultDuration(.osXDuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ class BaseLinesChartController: BaseChartController {
|
|||||||
updateChartRangeTitle(animated: animated)
|
updateChartRangeTitle(animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateChartRangeTitle(animated: Bool) {
|
override func updateChartRangeTitle(animated: Bool) {
|
||||||
let fromDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.lowerBound) + .hour)
|
let fromDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.lowerBound) + .hour)
|
||||||
let toDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.upperBound))
|
let toDate = Date(timeIntervalSince1970: TimeInterval(zoomedChartRange.upperBound))
|
||||||
if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) {
|
if Calendar.utc.startOfDay(for: fromDate) == Calendar.utc.startOfDay(for: toDate) {
|
||||||
@ -64,7 +64,7 @@ class BaseLinesChartController: BaseChartController {
|
|||||||
isChartInteractionBegun = false
|
isChartInteractionBegun = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ class GeneralLinesChartController: BaseLinesChartController {
|
|||||||
return visibleCharts
|
return visibleCharts
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
cancelChartInteraction()
|
cancelChartInteraction()
|
||||||
|
|
||||||
let horizontalRange = ClosedRange(uncheckedBounds:
|
let horizontalRange = ClosedRange(uncheckedBounds:
|
||||||
@ -183,8 +183,8 @@ class GeneralLinesChartController: BaseLinesChartController {
|
|||||||
updateChartRangeTitle(animated: true)
|
updateChartRangeTitle(animated: true)
|
||||||
|
|
||||||
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
|
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
|
||||||
updateHorizontalLimists(horizontalRange: horizontalRange, animated: true)
|
updateHorizontalLimists(horizontalRange: horizontalRange, animated: animated)
|
||||||
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true)
|
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {
|
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
|
@ -194,7 +194,7 @@ class TwoAxisLinesChartController: BaseLinesChartController {
|
|||||||
self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false)
|
self.setupChartCollection(chartsCollection: initialChartCollection, animated: true, isZoomed: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
cancelChartInteraction()
|
cancelChartInteraction()
|
||||||
|
|
||||||
let horizontalRange = ClosedRange(uncheckedBounds:
|
let horizontalRange = ClosedRange(uncheckedBounds:
|
||||||
@ -205,8 +205,8 @@ class TwoAxisLinesChartController: BaseLinesChartController {
|
|||||||
updateChartRangeTitle(animated: true)
|
updateChartRangeTitle(animated: true)
|
||||||
|
|
||||||
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
|
updateMainChartHorizontalRange(range: horizontalRange, animated: false)
|
||||||
updateHorizontalLimists(horizontalRange: horizontalRange, animated: true)
|
updateHorizontalLimists(horizontalRange: horizontalRange, animated: animated)
|
||||||
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: true)
|
updateVerticalLimitsAndRange(horizontalRange: horizontalRange, animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {
|
func updateMainChartHorizontalRange(range: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
|
@ -93,9 +93,9 @@ class PercentPieChartController: BaseChartController {
|
|||||||
|
|
||||||
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
TimeInterval.setDefaultSuration(.expandAnimationDuration)
|
TimeInterval.setDefaultDuration(.expandAnimationDuration)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .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 {
|
if isZoomed {
|
||||||
return pieController.chartRangeFractionDidUpdated(rangeFraction)
|
return pieController.chartRangeFractionDidUpdated(rangeFraction)
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,9 +84,9 @@ class DailyBarsChartController: BaseChartController {
|
|||||||
|
|
||||||
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
TimeInterval.setDefaultSuration(.expandAnimationDuration)
|
TimeInterval.setDefaultDuration(.expandAnimationDuration)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .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)
|
switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
if isZoomed {
|
if isZoomed {
|
||||||
return linesController.chartRangeFractionDidUpdated(rangeFraction)
|
return linesController.chartRangeFractionDidUpdated(rangeFraction)
|
||||||
} else {
|
} else {
|
||||||
|
@ -79,9 +79,9 @@ class StackedBarsChartController: BaseChartController {
|
|||||||
|
|
||||||
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
func switchToChart(chartsCollection: ChartsCollection, isZoomed: Bool, animated: Bool) {
|
||||||
if animated {
|
if animated {
|
||||||
TimeInterval.setDefaultSuration(.expandAnimationDuration)
|
TimeInterval.setDefaultDuration(.expandAnimationDuration)
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .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)
|
switchToChart(chartsCollection: barsController.chartsCollection, isZoomed: false, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>) {
|
override func updateChartRange(_ rangeFraction: ClosedRange<CGFloat>, animated: Bool) {
|
||||||
if isZoomed {
|
if isZoomed {
|
||||||
return zoomedBarsController.chartRangeFractionDidUpdated(rangeFraction)
|
return zoomedBarsController.chartRangeFractionDidUpdated(rangeFraction)
|
||||||
} else {
|
} else {
|
||||||
|
@ -21,7 +21,7 @@ extension TimeInterval {
|
|||||||
}
|
}
|
||||||
private static var innerDefaultDuration: TimeInterval = osXDuration
|
private static var innerDefaultDuration: TimeInterval = osXDuration
|
||||||
|
|
||||||
static func setDefaultSuration(_ duration: TimeInterval) {
|
static func setDefaultDuration(_ duration: TimeInterval) {
|
||||||
innerDefaultDuration = duration
|
innerDefaultDuration = duration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
self.chatListDisplayNode.chatListNode.toggleArchivedFolderHiddenByDefault = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -235,7 +235,9 @@ final class ChatListControllerNode: ASDisplayNode {
|
|||||||
if let requestAddContact = self?.requestAddContact {
|
if let requestAddContact = self?.requestAddContact {
|
||||||
requestAddContact(phoneNumber)
|
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 {
|
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||||
requestDeactivateSearch()
|
requestDeactivateSearch()
|
||||||
}
|
}
|
||||||
|
@ -627,7 +627,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
|
|
||||||
private let filter: ChatListNodePeersFilter
|
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.context = context
|
||||||
self.filter = filter
|
self.filter = filter
|
||||||
self.dimNode = ASDisplayNode()
|
self.dimNode = ASDisplayNode()
|
||||||
@ -1043,6 +1043,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
case .groupReference:
|
case .groupReference:
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}
|
}
|
||||||
|
}, present: { [weak self] c in
|
||||||
|
present(c)
|
||||||
})
|
})
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
|
|
||||||
@ -1390,8 +1392,24 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func clearRecentSearch() {
|
private func clearRecentSearch() {
|
||||||
let _ = (clearRecentlySearchedPeers(postbox: self.context.account.postbox)
|
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()
|
|> 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() {
|
override public func scrollToTop() {
|
||||||
|
@ -61,11 +61,12 @@ public final class ChatListNodeInteraction {
|
|||||||
let togglePeerMarkedUnread: (PeerId, Bool) -> Void
|
let togglePeerMarkedUnread: (PeerId, Bool) -> Void
|
||||||
let toggleArchivedFolderHiddenByDefault: () -> Void
|
let toggleArchivedFolderHiddenByDefault: () -> Void
|
||||||
let activateChatPreview: (ChatListItem, ASDisplayNode, ContextGesture?) -> Void
|
let activateChatPreview: (ChatListItem, ASDisplayNode, ContextGesture?) -> Void
|
||||||
|
let present: (ViewController) -> Void
|
||||||
|
|
||||||
public var searchTextHighightState: String?
|
public var searchTextHighightState: String?
|
||||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
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.activateSearch = activateSearch
|
||||||
self.peerSelected = peerSelected
|
self.peerSelected = peerSelected
|
||||||
self.disabledPeerSelected = disabledPeerSelected
|
self.disabledPeerSelected = disabledPeerSelected
|
||||||
@ -81,6 +82,7 @@ public final class ChatListNodeInteraction {
|
|||||||
self.togglePeerMarkedUnread = togglePeerMarkedUnread
|
self.togglePeerMarkedUnread = togglePeerMarkedUnread
|
||||||
self.toggleArchivedFolderHiddenByDefault = toggleArchivedFolderHiddenByDefault
|
self.toggleArchivedFolderHiddenByDefault = toggleArchivedFolderHiddenByDefault
|
||||||
self.activateChatPreview = activateChatPreview
|
self.activateChatPreview = activateChatPreview
|
||||||
|
self.present = present
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,6 +360,7 @@ public final class ChatListNode: ListView {
|
|||||||
public var deletePeerChat: ((PeerId) -> Void)?
|
public var deletePeerChat: ((PeerId) -> Void)?
|
||||||
public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
||||||
public var presentAlert: ((String) -> Void)?
|
public var presentAlert: ((String) -> Void)?
|
||||||
|
public var present: ((ViewController) -> Void)?
|
||||||
public var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
public var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
||||||
public var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)?
|
public var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
@ -562,6 +565,8 @@ public final class ChatListNode: ListView {
|
|||||||
} else {
|
} else {
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}
|
}
|
||||||
|
}, present: { [weak self] c in
|
||||||
|
self?.present?(c)
|
||||||
})
|
})
|
||||||
|
|
||||||
let viewProcessingQueue = self.viewProcessingQueue
|
let viewProcessingQueue = self.viewProcessingQueue
|
||||||
|
@ -354,6 +354,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
|||||||
|
|
||||||
let trackingRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.trackingGesture(_:)))
|
let trackingRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.trackingGesture(_:)))
|
||||||
trackingRecognizer.delegate = self
|
trackingRecognizer.delegate = self
|
||||||
|
trackingRecognizer.cancelsTouchesInView = false
|
||||||
self.view.addGestureRecognizer(trackingRecognizer)
|
self.view.addGestureRecognizer(trackingRecognizer)
|
||||||
|
|
||||||
self.view.addGestureRecognizer(ListViewReorderingGestureRecognizer(shouldBegin: { [weak self] point in
|
self.view.addGestureRecognizer(ListViewReorderingGestureRecognizer(shouldBegin: { [weak self] point in
|
||||||
|
@ -28,6 +28,11 @@ public final class ListViewScroller: UIScrollView, UIGestureRecognizerDelegate {
|
|||||||
return gestureRecognizer.numberOfTouches < 2
|
return gestureRecognizer.numberOfTouches < 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let view = gestureRecognizer.view?.hitTest(gestureRecognizer.location(in: gestureRecognizer.view), with: nil) as? UIControl {
|
||||||
|
return !view.isTracking
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
|
@ -71,6 +71,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
}, toggleArchivedFolderHiddenByDefault: {
|
}, toggleArchivedFolderHiddenByDefault: {
|
||||||
}, activateChatPreview: { _, _, gesture in
|
}, activateChatPreview: { _, _, gesture in
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
|
}, present: { _ in
|
||||||
})
|
})
|
||||||
|
|
||||||
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)
|
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)
|
||||||
|
@ -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
|
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()
|
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 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>()
|
let peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
@ -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
|
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()
|
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)
|
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)
|
||||||
|
|
||||||
|
@ -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
|
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()
|
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)
|
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)
|
||||||
|
|
||||||
|
@ -36,28 +36,28 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
case overview(PresentationTheme, ChannelStats)
|
case overview(PresentationTheme, ChannelStats)
|
||||||
|
|
||||||
case growthTitle(PresentationTheme, String)
|
case growthTitle(PresentationTheme, String)
|
||||||
case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case growthGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case followersTitle(PresentationTheme, String)
|
case followersTitle(PresentationTheme, String)
|
||||||
case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case followersGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case notificationsTitle(PresentationTheme, String)
|
case notificationsTitle(PresentationTheme, String)
|
||||||
case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case notificationsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case viewsByHourTitle(PresentationTheme, String)
|
case viewsByHourTitle(PresentationTheme, String)
|
||||||
case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case viewsByHourGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case postInteractionsTitle(PresentationTheme, String)
|
case postInteractionsTitle(PresentationTheme, String)
|
||||||
case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case postInteractionsGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case viewsBySourceTitle(PresentationTheme, String)
|
case viewsBySourceTitle(PresentationTheme, String)
|
||||||
case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case viewsBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case followersBySourceTitle(PresentationTheme, String)
|
case followersBySourceTitle(PresentationTheme, String)
|
||||||
case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case followersBySourceGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
case languagesTitle(PresentationTheme, String)
|
case languagesTitle(PresentationTheme, String)
|
||||||
case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, String, ChannelStatsGraph)
|
case languagesGraph(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, ChannelStatsGraph)
|
||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
@ -143,8 +143,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .growthGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .growthGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .growthGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .growthGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -155,8 +155,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .followersGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .followersGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .followersGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .followersGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -167,8 +167,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .notificationsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .notificationsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .notificationsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .notificationsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -179,8 +179,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .viewsByHourGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .viewsByHourGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .viewsByHourGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .viewsByHourGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -191,8 +191,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .postInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .postInteractionsGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .postInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .postInteractionsGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -203,8 +203,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .viewsBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .viewsBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .viewsBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .viewsBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -215,8 +215,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .followersBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .followersBySourceGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .followersBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .followersBySourceGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -227,8 +227,8 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .languagesGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsText, lhsGraph):
|
case let .languagesGraph(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsGraph):
|
||||||
if case let .languagesGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsText, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsText == rhsText, lhsGraph == rhsGraph {
|
if case let .languagesGraph(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsGraph) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsGraph == rhsGraph {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -254,15 +254,15 @@ private enum StatsEntry: ItemListNodeEntry {
|
|||||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||||
case let .overview(theme, stats):
|
case let .overview(theme, stats):
|
||||||
return StatsOverviewItem(presentationData: presentationData, stats: stats, sectionId: self.section, style: .blocks)
|
return StatsOverviewItem(presentationData: presentationData, stats: stats, sectionId: self.section, style: .blocks)
|
||||||
case let .growthGraph(theme, strings, dateTimeFormat, title, graph),
|
case let .growthGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .followersGraph(theme, strings, dateTimeFormat, title, graph),
|
let .followersGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .notificationsGraph(theme, strings, dateTimeFormat, title, graph),
|
let .notificationsGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .viewsByHourGraph(theme, strings, dateTimeFormat, title, graph),
|
let .viewsByHourGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .postInteractionsGraph(theme, strings, dateTimeFormat, title, graph),
|
let .postInteractionsGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .viewsBySourceGraph(theme, strings, dateTimeFormat, title, graph),
|
let .viewsBySourceGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .followersBySourceGraph(theme, strings, dateTimeFormat, title, graph),
|
let .followersBySourceGraph(theme, strings, dateTimeFormat, graph),
|
||||||
let .languagesGraph(theme, strings, dateTimeFormat, title, graph):
|
let .languagesGraph(theme, strings, dateTimeFormat, graph):
|
||||||
return StatsGraphItem(presentationData: presentationData, title: title, graph: graph, sectionId: self.section, style: .blocks)
|
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] = []
|
var entries: [StatsEntry] = []
|
||||||
|
|
||||||
if let data = data {
|
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(.overview(presentationData.theme, data))
|
||||||
|
|
||||||
entries.append(.growthTitle(presentationData.theme, "GROWTH"))
|
entries.append(.growthTitle(presentationData.theme, presentationData.strings.Stats_GrowthTitle))
|
||||||
entries.append(.growthGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Growth", data.growthGraph))
|
entries.append(.growthGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.growthGraph))
|
||||||
|
|
||||||
entries.append(.followersTitle(presentationData.theme, "FOLLOWERS"))
|
entries.append(.followersTitle(presentationData.theme, presentationData.strings.Stats_FollowersTitle))
|
||||||
entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Followers", data.followersGraph))
|
entries.append(.followersGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.followersGraph))
|
||||||
|
|
||||||
entries.append(.notificationsTitle(presentationData.theme, "NOTIFICATIONS"))
|
entries.append(.notificationsTitle(presentationData.theme, presentationData.strings.Stats_NotificationsTitle))
|
||||||
entries.append(.notificationsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, "Notifications", data.muteGraph))
|
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
|
return entries
|
||||||
@ -321,8 +324,13 @@ public func channelStatsController(context: AccountContext, peer: Peer, cachedPe
|
|||||||
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get())
|
let signal = combineLatest(context.sharedContext.presentationData, dataPromise.get())
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|> 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 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))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
@ -345,5 +353,6 @@ public func channelStatsController(context: AccountContext, peer: Peer, cachedPe
|
|||||||
controller.present(c, in: .window(.root), with: a)
|
controller.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
@ -12,14 +12,12 @@ import Charts
|
|||||||
|
|
||||||
class StatsGraphItem: ListViewItem, ItemListItem {
|
class StatsGraphItem: ListViewItem, ItemListItem {
|
||||||
let presentationData: ItemListPresentationData
|
let presentationData: ItemListPresentationData
|
||||||
let title: String
|
|
||||||
let graph: ChannelStatsGraph
|
let graph: ChannelStatsGraph
|
||||||
let sectionId: ItemListSectionId
|
let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
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.presentationData = presentationData
|
||||||
self.title = title
|
|
||||||
self.graph = graph
|
self.graph = graph
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
self.style = style
|
self.style = style
|
||||||
@ -117,12 +115,12 @@ class StatsGraphItemNode: ListViewItemNode {
|
|||||||
case .plain:
|
case .plain:
|
||||||
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
|
itemBackgroundColor = item.presentationData.theme.list.plainBackgroundColor
|
||||||
itemSeparatorColor = item.presentationData.theme.list.itemPlainSeparatorColor
|
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)
|
insets = itemListNeighborsPlainInsets(neighbors)
|
||||||
case .blocks:
|
case .blocks:
|
||||||
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
itemBackgroundColor = item.presentationData.theme.list.itemBlocksBackgroundColor
|
||||||
itemSeparatorColor = item.presentationData.theme.list.itemBlocksSeparatorColor
|
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)
|
insets = itemListNeighborsGroupedInsets(neighbors)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +136,6 @@ class StatsGraphItemNode: ListViewItemNode {
|
|||||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
||||||
if let updatedGraph = updatedGraph, case let .Loaded(data) = updatedGraph {
|
|
||||||
strongSelf.chartNode.setup(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch item.style {
|
switch item.style {
|
||||||
case .plain:
|
case .plain:
|
||||||
if strongSelf.backgroundNode.supernode != nil {
|
if strongSelf.backgroundNode.supernode != nil {
|
||||||
@ -179,12 +173,17 @@ class StatsGraphItemNode: ListViewItemNode {
|
|||||||
bottomStripeInset = 0.0
|
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.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.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.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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -151,32 +151,60 @@ class StatsOverviewItemNode: ListViewItemNode {
|
|||||||
updatedTheme = item.presentationData.theme
|
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 titleFont = Font.regular(item.presentationData.fontSize.itemListBaseHeaderFontSize)
|
||||||
let deltaFont = 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: "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 (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 (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 (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 (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()))
|
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: 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: "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 (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 (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 (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 (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 (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 (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 (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 (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 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 (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 (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 (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 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: 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 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 contentSize: CGSize
|
||||||
let insets: UIEdgeInsets
|
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.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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) }
|
dict[-1269012015] = { return Api.messages.AffectedHistory.parse_affectedHistory($0) }
|
||||||
dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) }
|
dict[1244130093] = { return Api.StatsGraph.parse_statsGraphAsync($0) }
|
||||||
dict[-1092839390] = { return Api.StatsGraph.parse_statsGraphError($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[-1036572727] = { return Api.account.PasswordInputSettings.parse_passwordInputSettings($0) }
|
||||||
dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) }
|
dict[878078826] = { return Api.PageTableCell.parse_pageTableCell($0) }
|
||||||
dict[-1626209256] = { return Api.ChatBannedRights.parse_chatBannedRights($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[-1837345356] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) }
|
||||||
dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) }
|
dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) }
|
||||||
dict[-368917890] = { return Api.PaymentCharge.parse_paymentCharge($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[-484987010] = { return Api.Updates.parse_updatesTooLong($0) }
|
||||||
dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) }
|
dict[-1857044719] = { return Api.Updates.parse_updateShortMessage($0) }
|
||||||
dict[377562760] = { return Api.Updates.parse_updateShortChatMessage($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[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) }
|
||||||
dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) }
|
dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) }
|
||||||
dict[-1531132162] = { return Api.updates.ChannelDifference.parse_channelDifferenceTooLong($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[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) }
|
||||||
dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) }
|
dict[-264117680] = { return Api.ChatOnlines.parse_chatOnlines($0) }
|
||||||
dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) }
|
dict[488313413] = { return Api.InputAppEvent.parse_inputAppEvent($0) }
|
||||||
@ -1225,6 +1225,8 @@ public struct Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.PaymentCharge:
|
case let _1 as Api.PaymentCharge:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.MessageInteractionCounters:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.stats.BroadcastStats:
|
case let _1 as Api.stats.BroadcastStats:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.Updates:
|
case let _1 as Api.Updates:
|
||||||
@ -1413,8 +1415,6 @@ public struct Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.updates.ChannelDifference:
|
case let _1 as Api.updates.ChannelDifference:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.StatsRowAbsValueAndPrev:
|
|
||||||
_1.serialize(buffer, boxed)
|
|
||||||
case let _1 as Api.channels.AdminLogResults:
|
case let _1 as Api.channels.AdminLogResults:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.ChatOnlines:
|
case let _1 as Api.ChatOnlines:
|
||||||
|
@ -12044,7 +12044,7 @@ public extension Api {
|
|||||||
public enum StatsGraph: TypeConstructorDescription {
|
public enum StatsGraph: TypeConstructorDescription {
|
||||||
case statsGraphAsync(token: String)
|
case statsGraphAsync(token: String)
|
||||||
case statsGraphError(error: 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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -12060,11 +12060,13 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
serializeString(error, buffer: buffer, boxed: false)
|
serializeString(error, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .statsGraph(let json):
|
case .statsGraph(let flags, let json, let zoomToken):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1057809608)
|
buffer.appendInt32(-1901828938)
|
||||||
}
|
}
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
json.serialize(buffer, true)
|
json.serialize(buffer, true)
|
||||||
|
if Int(flags) & Int(1 << 0) != 0 {serializeString(zoomToken!, buffer: buffer, boxed: false)}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12075,8 +12077,8 @@ public extension Api {
|
|||||||
return ("statsGraphAsync", [("token", token)])
|
return ("statsGraphAsync", [("token", token)])
|
||||||
case .statsGraphError(let error):
|
case .statsGraphError(let error):
|
||||||
return ("statsGraphError", [("error", error)])
|
return ("statsGraphError", [("error", error)])
|
||||||
case .statsGraph(let json):
|
case .statsGraph(let flags, let json, let zoomToken):
|
||||||
return ("statsGraph", [("json", json)])
|
return ("statsGraph", [("flags", flags), ("json", json), ("zoomToken", zoomToken)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12103,13 +12105,19 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static func parse_statsGraph(_ reader: BufferReader) -> StatsGraph? {
|
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() {
|
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
|
let _c1 = _1 != nil
|
||||||
if _c1 {
|
let _c2 = _2 != nil
|
||||||
return Api.StatsGraph.statsGraph(json: _1!)
|
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 {
|
else {
|
||||||
return nil
|
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 {
|
public enum Updates: TypeConstructorDescription {
|
||||||
case updatesTooLong
|
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 {
|
public enum ChatOnlines: TypeConstructorDescription {
|
||||||
case chatOnlines(onlines: Int32)
|
case chatOnlines(onlines: Int32)
|
||||||
|
@ -539,47 +539,40 @@ public struct payments {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
public struct stats {
|
public struct stats {
|
||||||
public enum BroadcastStats: TypeConstructorDescription {
|
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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(205195937)
|
buffer.appendInt32(821185690)
|
||||||
}
|
}
|
||||||
period.serialize(buffer, true)
|
period.serialize(buffer, true)
|
||||||
followers.serialize(buffer, true)
|
followers.serialize(buffer, true)
|
||||||
viewsPerPost.serialize(buffer, true)
|
viewsPerPost.serialize(buffer, true)
|
||||||
sharesPerPost.serialize(buffer, true)
|
sharesPerPost.serialize(buffer, true)
|
||||||
enabledNotifications.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)
|
growthGraph.serialize(buffer, true)
|
||||||
followersGraph.serialize(buffer, true)
|
followersGraph.serialize(buffer, true)
|
||||||
muteGraph.serialize(buffer, true)
|
muteGraph.serialize(buffer, true)
|
||||||
topHoursGraph.serialize(buffer, true)
|
topHoursGraph.serialize(buffer, true)
|
||||||
interactionsGraph.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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
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):
|
||||||
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)])
|
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() {
|
if let signature = reader.readInt32() {
|
||||||
_5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue
|
_5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue
|
||||||
}
|
}
|
||||||
var _6: [Api.StatsRowAbsValueAndPrev]?
|
var _6: Api.StatsGraph?
|
||||||
if let _ = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self)
|
_6 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||||
}
|
}
|
||||||
var _7: [Api.StatsRowAbsValueAndPrev]?
|
var _7: Api.StatsGraph?
|
||||||
if let _ = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self)
|
_7 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||||
}
|
}
|
||||||
var _8: [Api.StatsRowAbsValueAndPrev]?
|
var _8: Api.StatsGraph?
|
||||||
if let _ = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsRowAbsValueAndPrev.self)
|
_8 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
||||||
}
|
}
|
||||||
var _9: Api.StatsGraph?
|
var _9: Api.StatsGraph?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
@ -636,6 +629,10 @@ public struct stats {
|
|||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
_13 = Api.parse(reader, signature: signature) as? Api.StatsGraph
|
_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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -649,8 +646,9 @@ public struct stats {
|
|||||||
let _c11 = _11 != nil
|
let _c11 = _11 != nil
|
||||||
let _c12 = _12 != nil
|
let _c12 = _12 != nil
|
||||||
let _c13 = _13 != nil
|
let _c13 = _13 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
|
let _c14 = _14 != nil
|
||||||
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!)
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -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()
|
let buffer = Buffer()
|
||||||
buffer.appendInt32(1749505346)
|
buffer.appendInt32(1646092192)
|
||||||
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeString(token, 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)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.StatsGraph?
|
var result: Api.StatsGraph?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
@ -16,7 +16,7 @@ public struct ChannelStatsValue: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct ChannelStatsPercentValue: Equatable {
|
public struct ChannelStatsPercentValue: Equatable {
|
||||||
public let fraction: Double
|
public let value: Double
|
||||||
public let total: Double
|
public let total: Double
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ extension ChannelStatsPercentValue {
|
|||||||
init(apiPercentValue: Api.StatsPercentValue) {
|
init(apiPercentValue: Api.StatsPercentValue) {
|
||||||
switch apiPercentValue {
|
switch apiPercentValue {
|
||||||
case let .statsPercentValue(part, total):
|
case let .statsPercentValue(part, total):
|
||||||
self = ChannelStatsPercentValue(fraction: part, total: total)
|
self = ChannelStatsPercentValue(value: part, total: total)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,4 +435,3 @@ extension ChannelStats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -202,6 +202,7 @@ framework(
|
|||||||
"//submodules/SemanticStatusNode:SemanticStatusNode",
|
"//submodules/SemanticStatusNode:SemanticStatusNode",
|
||||||
"//submodules/AccountUtils:AccountUtils",
|
"//submodules/AccountUtils:AccountUtils",
|
||||||
"//submodules/Svg:Svg",
|
"//submodules/Svg:Svg",
|
||||||
|
"//submodules/StatisticsUI:StatisticsUI",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -1362,32 +1362,61 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = (getBankCardInfo(account: strongSelf.context.account, cardNumber: number)
|
// var signal = getBankCardInfo(account: strongSelf.context.account, cardNumber: number)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] info in
|
//
|
||||||
if let strongSelf = self, let info = info {
|
// var cancelImpl: (() -> Void)?
|
||||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
// let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
var items: [ActionSheetItem] = []
|
// let progressSignal = Signal<Never, NoError> { subscriber in
|
||||||
items.append(ActionSheetTextItem(title: info.title))
|
// let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||||
for url in info.urls {
|
// cancelImpl?()
|
||||||
items.append(ActionSheetButtonItem(title: url.title, color: .accent, action: { [weak actionSheet] in
|
// }))
|
||||||
actionSheet?.dismissAnimated()
|
// strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
if let strongSelf = self {
|
// return ActionDisposable { [weak controller] in
|
||||||
strongSelf.controllerInteraction?.openUrl(url.url, false, false, message)
|
// Queue.mainQueue().async() {
|
||||||
}
|
// controller?.dismiss()
|
||||||
}))
|
// }
|
||||||
}
|
// }
|
||||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
// }
|
||||||
actionSheet?.dismissAnimated()
|
// |> runOn(Queue.mainQueue())
|
||||||
UIPasteboard.general.string = number
|
// |> delay(0.15, queue: Queue.mainQueue())
|
||||||
}))
|
// let progressDisposable = progressSignal.start()
|
||||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
//
|
||||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
// signal = signal
|
||||||
actionSheet?.dismissAnimated()
|
// |> afterDisposed {
|
||||||
})
|
// Queue.mainQueue().async {
|
||||||
])])
|
// progressDisposable.dispose()
|
||||||
strongSelf.present(actionSheet, in: .window(.root))
|
// }
|
||||||
}
|
// }
|
||||||
})
|
// 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()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
|||||||
default:
|
default:
|
||||||
gesture?.cancel()
|
gesture?.cancel()
|
||||||
}
|
}
|
||||||
|
}, present: { _ in
|
||||||
})
|
})
|
||||||
interaction.searchTextHighightState = searchQuery
|
interaction.searchTextHighightState = searchQuery
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
|
import SyncCore
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
@ -36,6 +36,7 @@ import LocationResources
|
|||||||
import LocationUI
|
import LocationUI
|
||||||
import Geocoding
|
import Geocoding
|
||||||
import TextFormat
|
import TextFormat
|
||||||
|
import StatisticsUI
|
||||||
|
|
||||||
protocol PeerInfoScreenItem: class {
|
protocol PeerInfoScreenItem: class {
|
||||||
var id: AnyHashable { get }
|
var id: AnyHashable { get }
|
||||||
@ -2215,6 +2216,13 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let channel = peer as? TelegramChannel {
|
} 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
|
var canReport = true
|
||||||
if channel.isVerified {
|
if channel.isVerified {
|
||||||
canReport = false
|
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) {
|
private func openReport(user: Bool) {
|
||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
|
@ -223,7 +223,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
if let requestOpenMessageFromSearch = self?.requestOpenMessageFromSearch {
|
if let requestOpenMessageFromSearch = self?.requestOpenMessageFromSearch {
|
||||||
requestOpenMessageFromSearch(peer, messageId)
|
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 {
|
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||||
requestDeactivateSearch()
|
requestDeactivateSearch()
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user