mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Temp
This commit is contained in:
parent
c954a55d2b
commit
c9fd9f2a16
@ -812,6 +812,9 @@ public protocol CollectibleItemInfoScreenInitialData: AnyObject {
|
||||
public protocol BusinessLinksSetupScreenInitialData: AnyObject {
|
||||
}
|
||||
|
||||
public protocol AffiliateProgramSetupScreenInitialData: AnyObject {
|
||||
}
|
||||
|
||||
public enum CollectibleItemInfoScreenSubject {
|
||||
case phoneNumber(String)
|
||||
case username(String)
|
||||
@ -1052,6 +1055,9 @@ public protocol SharedAccountContext: AnyObject {
|
||||
|
||||
func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, botPeer: EnginePeer, chatPeer: EnginePeer?, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?)
|
||||
|
||||
func makeAffiliateProgramSetupScreenInitialData(context: AccountContext, peerId: EnginePeer.Id) -> Signal<AffiliateProgramSetupScreenInitialData, NoError>
|
||||
func makeAffiliateProgramSetupScreen(context: AccountContext, initialData: AffiliateProgramSetupScreenInitialData) -> ViewController
|
||||
|
||||
func makeDebugSettingsController(context: AccountContext?) -> ViewController?
|
||||
|
||||
func navigateToCurrentCall()
|
||||
|
@ -1,15 +1,22 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public enum HStackAlignment {
|
||||
case left
|
||||
case alternatingLeftRight
|
||||
}
|
||||
|
||||
public final class HStack<ChildEnvironment: Equatable>: CombinedComponent {
|
||||
public typealias EnvironmentType = ChildEnvironment
|
||||
|
||||
private let items: [AnyComponentWithIdentity<ChildEnvironment>]
|
||||
private let spacing: CGFloat
|
||||
private let alignment: HStackAlignment
|
||||
|
||||
public init(_ items: [AnyComponentWithIdentity<ChildEnvironment>], spacing: CGFloat) {
|
||||
public init(_ items: [AnyComponentWithIdentity<ChildEnvironment>], spacing: CGFloat, alignment: HStackAlignment = .left) {
|
||||
self.items = items
|
||||
self.spacing = spacing
|
||||
self.alignment = alignment
|
||||
}
|
||||
|
||||
public static func ==(lhs: HStack<ChildEnvironment>, rhs: HStack<ChildEnvironment>) -> Bool {
|
||||
@ -19,6 +26,9 @@ public final class HStack<ChildEnvironment: Equatable>: CombinedComponent {
|
||||
if lhs.spacing != rhs.spacing {
|
||||
return false
|
||||
}
|
||||
if lhs.alignment != rhs.alignment {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -42,21 +52,51 @@ public final class HStack<ChildEnvironment: Equatable>: CombinedComponent {
|
||||
}
|
||||
|
||||
var size = CGSize(width: 0.0, height: 0.0)
|
||||
for child in updatedChildren {
|
||||
size.width += child.size.width
|
||||
size.height = max(size.height, child.size.height)
|
||||
}
|
||||
size.width += context.component.spacing * CGFloat(updatedChildren.count - 1)
|
||||
|
||||
var nextX = 0.0
|
||||
for child in updatedChildren {
|
||||
context.add(child
|
||||
.position(child.size.centered(in: CGRect(origin: CGPoint(x: nextX, y: floor((size.height - child.size.height) * 0.5)), size: child.size)).center)
|
||||
.appear(.default(scale: true, alpha: true))
|
||||
.disappear(.default(scale: true, alpha: true))
|
||||
)
|
||||
nextX += child.size.width
|
||||
nextX += context.component.spacing
|
||||
switch context.component.alignment {
|
||||
case .left:
|
||||
for child in updatedChildren {
|
||||
size.width += child.size.width
|
||||
size.height = max(size.height, child.size.height)
|
||||
}
|
||||
size.width += context.component.spacing * CGFloat(updatedChildren.count - 1)
|
||||
|
||||
var nextX = 0.0
|
||||
for child in updatedChildren {
|
||||
context.add(child
|
||||
.position(child.size.centered(in: CGRect(origin: CGPoint(x: nextX, y: floor((size.height - child.size.height) * 0.5)), size: child.size)).center)
|
||||
.appear(.default(scale: true, alpha: true))
|
||||
.disappear(.default(scale: true, alpha: true))
|
||||
)
|
||||
nextX += child.size.width
|
||||
nextX += context.component.spacing
|
||||
}
|
||||
case .alternatingLeftRight:
|
||||
size.width = context.availableSize.width
|
||||
for child in updatedChildren {
|
||||
size.height = max(size.height, child.size.height)
|
||||
}
|
||||
|
||||
var nextLeftX = 0.0
|
||||
var nextRightX = size.width
|
||||
for i in 0 ..< updatedChildren.count {
|
||||
let child = updatedChildren[i]
|
||||
let childFrame: CGRect
|
||||
if i % 2 == 0 {
|
||||
childFrame = CGRect(origin: CGPoint(x: nextLeftX, y: floor((size.height - child.size.height) * 0.5)), size: child.size)
|
||||
nextLeftX += child.size.width
|
||||
nextLeftX += context.component.spacing
|
||||
} else {
|
||||
childFrame = CGRect(origin: CGPoint(x: nextRightX - child.size.width, y: floor((size.height - child.size.height) * 0.5)), size: child.size)
|
||||
nextRightX -= child.size.width
|
||||
nextRightX -= context.component.spacing
|
||||
}
|
||||
|
||||
context.add(child
|
||||
.position(child.size.centered(in: childFrame).center)
|
||||
.appear(.default(scale: true, alpha: true))
|
||||
.disappear(.default(scale: true, alpha: true))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return size
|
||||
|
@ -462,6 +462,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Stars/StarsIntroScreen",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftOptionsScreen",
|
||||
"//submodules/TelegramUI/Components/ContentReportScreen",
|
||||
"//submodules/TelegramUI/Components/PeerInfo/AffiliateProgramSetupScreen",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
"//build-system:ios_sim_arm64": [],
|
||||
|
@ -1363,42 +1363,44 @@ private final class ChatSendStarsScreenComponent: Component {
|
||||
let sliderSize = self.slider.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SliderComponent(
|
||||
valueCount: self.amount.maxSliderValue + 1,
|
||||
value: self.amount.sliderValue,
|
||||
markPositions: false,
|
||||
content: .discrete(SliderComponent.Discrete(
|
||||
valueCount: self.amount.maxSliderValue + 1,
|
||||
value: self.amount.sliderValue,
|
||||
markPositions: false,
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.amount = self.amount.withSliderValue(value)
|
||||
self.didChangeAmount = true
|
||||
|
||||
self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint()))
|
||||
|
||||
let sliderValue = Float(value) / Float(component.maxAmount)
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
|
||||
if let previousTimestamp {
|
||||
let deltaTime = currentTimestamp - previousTimestamp
|
||||
let delta = sliderValue - self.previousSliderValue
|
||||
let deltaValue = abs(sliderValue - self.previousSliderValue)
|
||||
|
||||
let speed = deltaValue / Float(deltaTime)
|
||||
let newSpeed = max(0, min(65.0, speed * 70.0))
|
||||
|
||||
if newSpeed < 0.01 && deltaValue < 0.001 {
|
||||
} else {
|
||||
self.badgeStars.update(speed: newSpeed, delta: delta)
|
||||
}
|
||||
}
|
||||
|
||||
self.previousSliderValue = sliderValue
|
||||
self.previousTimestamp = currentTimestamp
|
||||
}
|
||||
)),
|
||||
trackBackgroundColor: .clear,
|
||||
trackForegroundColor: .clear,
|
||||
knobSize: 26.0,
|
||||
knobColor: .white,
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.amount = self.amount.withSliderValue(value)
|
||||
self.didChangeAmount = true
|
||||
|
||||
self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint()))
|
||||
|
||||
let sliderValue = Float(value) / Float(component.maxAmount)
|
||||
let currentTimestamp = CACurrentMediaTime()
|
||||
|
||||
if let previousTimestamp {
|
||||
let deltaTime = currentTimestamp - previousTimestamp
|
||||
let delta = sliderValue - self.previousSliderValue
|
||||
let deltaValue = abs(sliderValue - self.previousSliderValue)
|
||||
|
||||
let speed = deltaValue / Float(deltaTime)
|
||||
let newSpeed = max(0, min(65.0, speed * 70.0))
|
||||
|
||||
if newSpeed < 0.01 && deltaValue < 0.001 {
|
||||
} else {
|
||||
self.badgeStars.update(speed: newSpeed, delta: delta)
|
||||
}
|
||||
}
|
||||
|
||||
self.previousSliderValue = sliderValue
|
||||
self.previousTimestamp = currentTimestamp
|
||||
},
|
||||
isTrackingUpdated: { [weak self] isTracking in
|
||||
guard let self else {
|
||||
return
|
||||
|
@ -9,43 +9,91 @@ import ListSectionComponent
|
||||
import SliderComponent
|
||||
|
||||
public final class ListItemSliderSelectorComponent: Component {
|
||||
public final class Discrete: Equatable {
|
||||
public let values: [String]
|
||||
public let markPositions: Bool
|
||||
public let selectedIndex: Int
|
||||
public let title: String?
|
||||
public let selectedIndexUpdated: (Int) -> Void
|
||||
|
||||
public init(values: [String], markPositions: Bool, selectedIndex: Int, title: String?, selectedIndexUpdated: @escaping (Int) -> Void) {
|
||||
self.values = values
|
||||
self.markPositions = markPositions
|
||||
self.selectedIndex = selectedIndex
|
||||
self.title = title
|
||||
self.selectedIndexUpdated = selectedIndexUpdated
|
||||
}
|
||||
|
||||
public static func ==(lhs: Discrete, rhs: Discrete) -> Bool {
|
||||
if lhs.values != rhs.values {
|
||||
return false
|
||||
}
|
||||
if lhs.markPositions != rhs.markPositions {
|
||||
return false
|
||||
}
|
||||
if lhs.selectedIndex != rhs.selectedIndex {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public final class Continuous: Equatable {
|
||||
public let value: CGFloat
|
||||
public let lowerBoundTitle: String
|
||||
public let upperBoundTitle: String
|
||||
public let title: String
|
||||
public let valueUpdated: (CGFloat) -> Void
|
||||
|
||||
public init(value: CGFloat, lowerBoundTitle: String, upperBoundTitle: String, title: String, valueUpdated: @escaping (CGFloat) -> Void) {
|
||||
self.value = value
|
||||
self.lowerBoundTitle = lowerBoundTitle
|
||||
self.upperBoundTitle = upperBoundTitle
|
||||
self.title = title
|
||||
self.valueUpdated = valueUpdated
|
||||
}
|
||||
|
||||
public static func ==(lhs: Continuous, rhs: Continuous) -> Bool {
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
if lhs.lowerBoundTitle != rhs.lowerBoundTitle {
|
||||
return false
|
||||
}
|
||||
if lhs.upperBoundTitle != rhs.upperBoundTitle {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public enum Content: Equatable {
|
||||
case discrete(Discrete)
|
||||
case continuous(Continuous)
|
||||
}
|
||||
|
||||
public let theme: PresentationTheme
|
||||
public let values: [String]
|
||||
public let markPositions: Bool
|
||||
public let selectedIndex: Int
|
||||
public let title: String?
|
||||
public let selectedIndexUpdated: (Int) -> Void
|
||||
public let content: Content
|
||||
|
||||
public init(
|
||||
theme: PresentationTheme,
|
||||
values: [String],
|
||||
markPositions: Bool,
|
||||
selectedIndex: Int,
|
||||
title: String?,
|
||||
selectedIndexUpdated: @escaping (Int) -> Void
|
||||
content: Content
|
||||
) {
|
||||
self.theme = theme
|
||||
self.values = values
|
||||
self.markPositions = markPositions
|
||||
self.selectedIndex = selectedIndex
|
||||
self.title = title
|
||||
self.selectedIndexUpdated = selectedIndexUpdated
|
||||
self.content = content
|
||||
}
|
||||
|
||||
public static func ==(lhs: ListItemSliderSelectorComponent, rhs: ListItemSliderSelectorComponent) -> Bool {
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.values != rhs.values {
|
||||
return false
|
||||
}
|
||||
if lhs.markPositions != rhs.markPositions {
|
||||
return false
|
||||
}
|
||||
if lhs.selectedIndex != rhs.selectedIndex {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -81,48 +129,90 @@ public final class ListItemSliderSelectorComponent: Component {
|
||||
let titleAreaWidth: CGFloat = availableSize.width - titleSideInset * 2.0
|
||||
|
||||
var validIds: [Int] = []
|
||||
for i in 0 ..< component.values.count {
|
||||
if component.title != nil {
|
||||
if i != 0 && i != component.values.count - 1 {
|
||||
continue
|
||||
var mainTitleValue: String?
|
||||
|
||||
switch component.content {
|
||||
case let .discrete(discrete):
|
||||
mainTitleValue = discrete.title
|
||||
|
||||
for i in 0 ..< discrete.values.count {
|
||||
if discrete.title != nil {
|
||||
if i != 0 && i != discrete.values.count - 1 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
validIds.append(i)
|
||||
|
||||
var titleTransition = transition
|
||||
let title: ComponentView<Empty>
|
||||
if let current = self.titles[i] {
|
||||
title = current
|
||||
} else {
|
||||
titleTransition = titleTransition.withAnimation(.none)
|
||||
title = ComponentView()
|
||||
self.titles[i] = title
|
||||
}
|
||||
let titleSize = title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: discrete.values[i], font: Font.regular(13.0), textColor: component.theme.list.itemSecondaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
var titleFrame = CGRect(origin: CGPoint(x: titleSideInset - floor(titleSize.width * 0.5), y: 14.0), size: titleSize)
|
||||
if discrete.values.count > 1 {
|
||||
titleFrame.origin.x += floor(CGFloat(i) / CGFloat(discrete.values.count - 1) * titleAreaWidth)
|
||||
}
|
||||
if titleFrame.minX < titleClippingSideInset {
|
||||
titleFrame.origin.x = titleSideInset
|
||||
}
|
||||
if titleFrame.maxX > availableSize.width - titleClippingSideInset {
|
||||
titleFrame.origin.x = availableSize.width - titleClippingSideInset - titleSize.width
|
||||
}
|
||||
if let titleView = title.view {
|
||||
if titleView.superview == nil {
|
||||
self.addSubview(titleView)
|
||||
}
|
||||
titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
|
||||
titleTransition.setPosition(view: titleView, position: titleFrame.center)
|
||||
}
|
||||
}
|
||||
case let .continuous(continuous):
|
||||
mainTitleValue = continuous.title
|
||||
|
||||
validIds.append(i)
|
||||
|
||||
var titleTransition = transition
|
||||
let title: ComponentView<Empty>
|
||||
if let current = self.titles[i] {
|
||||
title = current
|
||||
} else {
|
||||
titleTransition = titleTransition.withAnimation(.none)
|
||||
title = ComponentView()
|
||||
self.titles[i] = title
|
||||
}
|
||||
let titleSize = title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: component.values[i], font: Font.regular(13.0), textColor: component.theme.list.itemSecondaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
var titleFrame = CGRect(origin: CGPoint(x: titleSideInset - floor(titleSize.width * 0.5), y: 14.0), size: titleSize)
|
||||
if component.values.count > 1 {
|
||||
titleFrame.origin.x += floor(CGFloat(i) / CGFloat(component.values.count - 1) * titleAreaWidth)
|
||||
}
|
||||
if titleFrame.minX < titleClippingSideInset {
|
||||
titleFrame.origin.x = titleSideInset
|
||||
}
|
||||
if titleFrame.maxX > availableSize.width - titleClippingSideInset {
|
||||
titleFrame.origin.x = availableSize.width - titleClippingSideInset - titleSize.width
|
||||
}
|
||||
if let titleView = title.view {
|
||||
if titleView.superview == nil {
|
||||
self.addSubview(titleView)
|
||||
for i in 0 ..< 2 {
|
||||
validIds.append(i)
|
||||
|
||||
var titleTransition = transition
|
||||
let title: ComponentView<Empty>
|
||||
if let current = self.titles[i] {
|
||||
title = current
|
||||
} else {
|
||||
titleTransition = titleTransition.withAnimation(.none)
|
||||
title = ComponentView()
|
||||
self.titles[i] = title
|
||||
}
|
||||
let titleSize = title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: i == 0 ? continuous.lowerBoundTitle : continuous.upperBoundTitle, font: Font.regular(13.0), textColor: component.theme.list.itemSecondaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
var titleFrame = CGRect(origin: CGPoint(x: titleSideInset, y: 14.0), size: titleSize)
|
||||
if i == 1 {
|
||||
titleFrame.origin.x = availableSize.width - titleClippingSideInset - titleSize.width
|
||||
}
|
||||
if let titleView = title.view {
|
||||
if titleView.superview == nil {
|
||||
self.addSubview(titleView)
|
||||
}
|
||||
titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
|
||||
titleTransition.setPosition(view: titleView, position: titleFrame.center)
|
||||
}
|
||||
titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
|
||||
titleTransition.setPosition(view: titleView, position: titleFrame.center)
|
||||
}
|
||||
}
|
||||
var removeIds: [Int] = []
|
||||
@ -136,7 +226,7 @@ public final class ListItemSliderSelectorComponent: Component {
|
||||
self.titles.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
if let title = component.title {
|
||||
if let title = mainTitleValue {
|
||||
let mainTitle: ComponentView<Empty>
|
||||
var mainTitleTransition = transition
|
||||
if let current = self.mainTitle {
|
||||
@ -169,24 +259,50 @@ public final class ListItemSliderSelectorComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let sliderSize = self.slider.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SliderComponent(
|
||||
valueCount: component.values.count,
|
||||
value: component.selectedIndex,
|
||||
markPositions: component.markPositions,
|
||||
trackBackgroundColor: component.theme.list.controlSecondaryColor,
|
||||
trackForegroundColor: component.theme.list.itemAccentColor,
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.selectedIndexUpdated(value)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100.0)
|
||||
)
|
||||
let sliderSize: CGSize
|
||||
switch component.content {
|
||||
case let .discrete(discrete):
|
||||
sliderSize = self.slider.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SliderComponent(
|
||||
content: .discrete(SliderComponent.Discrete(
|
||||
valueCount: discrete.values.count,
|
||||
value: discrete.selectedIndex,
|
||||
markPositions: discrete.markPositions,
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self, let component = self.component, case let .discrete(discrete) = component.content else {
|
||||
return
|
||||
}
|
||||
discrete.selectedIndexUpdated(value)
|
||||
})
|
||||
),
|
||||
trackBackgroundColor: component.theme.list.controlSecondaryColor,
|
||||
trackForegroundColor: component.theme.list.itemAccentColor
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100.0)
|
||||
)
|
||||
case let .continuous(continuous):
|
||||
sliderSize = self.slider.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(SliderComponent(
|
||||
content: .continuous(SliderComponent.Continuous(
|
||||
value: continuous.value,
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self, let component = self.component, case let .continuous(continuous) = component.content else {
|
||||
return
|
||||
}
|
||||
continuous.valueUpdated(value)
|
||||
})
|
||||
),
|
||||
trackBackgroundColor: component.theme.list.controlSecondaryColor,
|
||||
trackForegroundColor: component.theme.list.itemAccentColor
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100.0)
|
||||
)
|
||||
}
|
||||
|
||||
let sliderFrame = CGRect(origin: CGPoint(x: sideInset, y: 36.0), size: sliderSize)
|
||||
if let sliderView = self.slider.view {
|
||||
if sliderView.superview == nil {
|
||||
|
@ -1281,20 +1281,22 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
|
||||
theme: environment.theme,
|
||||
values: reactionCountValueList.map { item in
|
||||
return item
|
||||
},
|
||||
markPositions: false,
|
||||
selectedIndex: max(0, min(reactionCountValueList.count - 1, self.allowedReactionCount - 1)),
|
||||
title: sliderTitle,
|
||||
selectedIndexUpdated: { [weak self] index in
|
||||
guard let self else {
|
||||
return
|
||||
content: .discrete(ListItemSliderSelectorComponent.Discrete(
|
||||
values: reactionCountValueList.map { item in
|
||||
return item
|
||||
},
|
||||
markPositions: false,
|
||||
selectedIndex: max(0, min(reactionCountValueList.count - 1, self.allowedReactionCount - 1)),
|
||||
title: sliderTitle,
|
||||
selectedIndexUpdated: { [weak self] index in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let index = max(1, min(reactionCountValueList.count, index + 1))
|
||||
self.allowedReactionCount = index
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
let index = max(1, min(reactionCountValueList.count, index + 1))
|
||||
self.allowedReactionCount = index
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
))
|
||||
)))
|
||||
],
|
||||
displaySeparators: false
|
||||
|
@ -0,0 +1,36 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "AffiliateProgramSetupScreen",
|
||||
module_name = "AffiliateProgramSetupScreen",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/TelegramUI/Components/ButtonComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/ViewControllerComponent",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
"//submodules/TelegramUI/Components/ListSectionComponent",
|
||||
"//submodules/TelegramUI/Components/ListItemSliderSelectorComponent",
|
||||
"//submodules/TelegramUI/Components/ListActionItemComponent",
|
||||
"//submodules/Components/BlurredBackgroundComponent",
|
||||
"//submodules/Markdown",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
@ -0,0 +1,715 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import ComponentFlow
|
||||
import ComponentDisplayAdapters
|
||||
import AppBundle
|
||||
import ViewControllerComponent
|
||||
import AccountContext
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import MultilineTextComponent
|
||||
import ButtonComponent
|
||||
import UndoUI
|
||||
import BundleIconComponent
|
||||
import ListSectionComponent
|
||||
import ListItemSliderSelectorComponent
|
||||
import ListActionItemComponent
|
||||
import Markdown
|
||||
import BlurredBackgroundComponent
|
||||
|
||||
final class AffiliateProgramSetupScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let initialContent: AffiliateProgramSetupScreen.Content
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
initialContent: AffiliateProgramSetupScreen.Content
|
||||
) {
|
||||
self.context = context
|
||||
self.initialContent = initialContent
|
||||
}
|
||||
|
||||
static func ==(lhs: AffiliateProgramSetupScreenComponent, rhs: AffiliateProgramSetupScreenComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
final class View: UIView, UIScrollViewDelegate {
|
||||
private let scrollView: UIScrollView
|
||||
|
||||
private let title = ComponentView<Empty>()
|
||||
private let titleTransformContainer: UIView
|
||||
private let subtitle = ComponentView<Empty>()
|
||||
|
||||
private let introBackground = ComponentView<Empty>()
|
||||
private var introIconItems: [Int: ComponentView<Empty>] = [:]
|
||||
private var introTitleItems: [Int: ComponentView<Empty>] = [:]
|
||||
private var introTextItems: [Int: ComponentView<Empty>] = [:]
|
||||
|
||||
private let commissionSection = ComponentView<Empty>()
|
||||
private let durationSection = ComponentView<Empty>()
|
||||
private let existingProgramsSection = ComponentView<Empty>()
|
||||
private let endProgramSection = ComponentView<Empty>()
|
||||
|
||||
private let bottomPanelSeparator = SimpleLayer()
|
||||
private let bottomPanelBackground = ComponentView<Empty>()
|
||||
private let bottomPanelButton = ComponentView<Empty>()
|
||||
private let bottomPanelText = ComponentView<Empty>()
|
||||
|
||||
private var isUpdating: Bool = false
|
||||
|
||||
private var component: AffiliateProgramSetupScreenComponent?
|
||||
private(set) weak var state: EmptyComponentState?
|
||||
private var environment: EnvironmentType?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.scrollView = UIScrollView()
|
||||
self.scrollView.showsVerticalScrollIndicator = true
|
||||
self.scrollView.showsHorizontalScrollIndicator = false
|
||||
self.scrollView.scrollsToTop = false
|
||||
self.scrollView.delaysContentTouches = false
|
||||
self.scrollView.canCancelContentTouches = true
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
self.scrollView.alwaysBounceVertical = true
|
||||
|
||||
self.titleTransformContainer = UIView()
|
||||
self.scrollView.addSubview(self.titleTransformContainer)
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.scrollView.delegate = self
|
||||
self.addSubview(self.scrollView)
|
||||
|
||||
self.layer.addSublayer(self.bottomPanelSeparator)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
func scrollToTop() {
|
||||
self.scrollView.setContentOffset(CGPoint(), animated: true)
|
||||
}
|
||||
|
||||
func attemptNavigation(complete: @escaping () -> Void) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
self.updateScrolling(transition: .immediate)
|
||||
}
|
||||
|
||||
private func updateScrolling(transition: ComponentTransition) {
|
||||
let navigationAlphaDistance: CGFloat = 16.0
|
||||
let navigationAlpha: CGFloat = max(0.0, min(1.0, self.scrollView.contentOffset.y / navigationAlphaDistance))
|
||||
if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar {
|
||||
transition.setAlpha(layer: navigationBar.backgroundNode.layer, alpha: navigationAlpha)
|
||||
transition.setAlpha(layer: navigationBar.stripeNode.layer, alpha: navigationAlpha)
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: AffiliateProgramSetupScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
defer {
|
||||
self.isUpdating = false
|
||||
}
|
||||
|
||||
let environment = environment[EnvironmentType.self].value
|
||||
let themeUpdated = self.environment?.theme !== environment.theme
|
||||
self.environment = environment
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
|
||||
if themeUpdated {
|
||||
self.backgroundColor = environment.theme.list.blocksBackgroundColor
|
||||
self.bottomPanelSeparator.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor
|
||||
}
|
||||
|
||||
self.component = component
|
||||
self.state = state
|
||||
|
||||
let topInset: CGFloat = environment.navigationHeight + 87.0
|
||||
let bottomInset: CGFloat = 8.0
|
||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||
let textSideInset: CGFloat = 16.0
|
||||
let sectionSpacing: CGFloat = 24.0
|
||||
|
||||
var contentHeight: CGFloat = 0.0
|
||||
contentHeight += topInset
|
||||
|
||||
let titleSize = self.title.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: "Affiliate Program", font: Font.bold(30.0), textColor: environment.theme.list.itemPrimaryTextColor))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - textSideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: contentHeight), size: titleSize)
|
||||
if let titleView = self.title.view {
|
||||
if titleView.superview == nil {
|
||||
self.titleTransformContainer.addSubview(titleView)
|
||||
}
|
||||
titleView.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
|
||||
transition.setPosition(view: self.titleTransformContainer, position: titleFrame.center)
|
||||
}
|
||||
contentHeight += titleSize.height
|
||||
contentHeight += 10.0
|
||||
|
||||
let subtitleSize = self.subtitle.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: "Reward those who help grow your userbase.", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - textSideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
let subtitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - subtitleSize.width) * 0.5), y: contentHeight), size: subtitleSize)
|
||||
if let subtitleView = self.subtitle.view {
|
||||
if subtitleView.superview == nil {
|
||||
self.scrollView.addSubview(subtitleView)
|
||||
subtitleView.bounds = CGRect(origin: CGPoint(), size: subtitleFrame.size)
|
||||
transition.setPosition(view: subtitleView, position: subtitleFrame.center)
|
||||
}
|
||||
}
|
||||
contentHeight += subtitleSize.height
|
||||
contentHeight += 24.0
|
||||
|
||||
let introItems: [(icon: String, title: String, text: String)] = [
|
||||
(
|
||||
"Chat/Context Menu/Smile",
|
||||
"Share revenue with affiliates",
|
||||
"Set the commission for revenue generated by users referred to you."
|
||||
),
|
||||
(
|
||||
"Chat/Context Menu/Smile",
|
||||
"Launch your affiliate program",
|
||||
"Telegram will feature your program for millions of potential affiliates."
|
||||
),
|
||||
(
|
||||
"Chat/Context Menu/Smile",
|
||||
"Let affiliates promote you",
|
||||
"Affiliates will share your referral link with their audience."
|
||||
)
|
||||
]
|
||||
var introItemsHeight: CGFloat = 17.0
|
||||
let introItemIconX: CGFloat = sideInset + 19.0
|
||||
let introItemTextX: CGFloat = sideInset + 56.0
|
||||
let introItemTextRightInset: CGFloat = sideInset + 10.0
|
||||
let introItemSpacing: CGFloat = 22.0
|
||||
for i in 0 ..< introItems.count {
|
||||
if i != 0 {
|
||||
introItemsHeight += introItemSpacing
|
||||
}
|
||||
|
||||
let item = introItems[i]
|
||||
|
||||
let itemIcon: ComponentView<Empty>
|
||||
let itemTitle: ComponentView<Empty>
|
||||
let itemText: ComponentView<Empty>
|
||||
|
||||
if let current = self.introIconItems[i] {
|
||||
itemIcon = current
|
||||
} else {
|
||||
itemIcon = ComponentView()
|
||||
self.introIconItems[i] = itemIcon
|
||||
}
|
||||
|
||||
if let current = self.introTitleItems[i] {
|
||||
itemTitle = current
|
||||
} else {
|
||||
itemTitle = ComponentView()
|
||||
self.introTitleItems[i] = itemTitle
|
||||
}
|
||||
|
||||
if let current = self.introTextItems[i] {
|
||||
itemText = current
|
||||
} else {
|
||||
itemText = ComponentView()
|
||||
self.introTextItems[i] = itemText
|
||||
}
|
||||
|
||||
let iconSize = itemIcon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(BundleIconComponent(
|
||||
name: item.icon,
|
||||
tintColor: environment.theme.list.itemAccentColor
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
let titleSize = itemTitle.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: item.title, font: Font.semibold(15.0), textColor: environment.theme.list.itemPrimaryTextColor)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - introItemTextRightInset - introItemTextX, height: 1000.0)
|
||||
)
|
||||
let textSize = itemText.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: item.text, font: Font.regular(15.0), textColor: environment.theme.list.itemSecondaryTextColor)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - introItemTextRightInset - introItemTextX, height: 1000.0)
|
||||
)
|
||||
|
||||
let itemIconFrame = CGRect(origin: CGPoint(x: introItemIconX, y: contentHeight + introItemsHeight + 8.0), size: iconSize)
|
||||
let itemTitleFrame = CGRect(origin: CGPoint(x: introItemTextX, y: contentHeight + introItemsHeight), size: titleSize)
|
||||
let itemTextFrame = CGRect(origin: CGPoint(x: introItemTextX, y: itemTitleFrame.maxY + 5.0), size: textSize)
|
||||
|
||||
if let itemIconView = itemIcon.view {
|
||||
if itemIconView.superview == nil {
|
||||
self.scrollView.addSubview(itemIconView)
|
||||
}
|
||||
transition.setFrame(view: itemIconView, frame: itemIconFrame)
|
||||
}
|
||||
if let itemTitleView = itemTitle.view {
|
||||
if itemTitleView.superview == nil {
|
||||
itemTitleView.layer.anchorPoint = CGPoint()
|
||||
self.scrollView.addSubview(itemTitleView)
|
||||
}
|
||||
transition.setPosition(view: itemTitleView, position: itemTitleFrame.origin)
|
||||
itemTitleView.bounds = CGRect(origin: CGPoint(), size: itemTitleFrame.size)
|
||||
}
|
||||
if let itemTextView = itemText.view {
|
||||
if itemTextView.superview == nil {
|
||||
itemTextView.layer.anchorPoint = CGPoint()
|
||||
self.scrollView.addSubview(itemTextView)
|
||||
}
|
||||
transition.setPosition(view: itemTextView, position: itemTextFrame.origin)
|
||||
itemTextView.bounds = CGRect(origin: CGPoint(), size: itemTextFrame.size)
|
||||
}
|
||||
introItemsHeight = itemTextFrame.maxY - contentHeight
|
||||
}
|
||||
introItemsHeight += 19.0
|
||||
|
||||
let introBackgroundFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: CGSize(width: availableSize.width - sideInset * 2.0, height: introItemsHeight))
|
||||
let _ = self.introBackground.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(FilledRoundedRectangleComponent(
|
||||
color: environment.theme.list.itemBlocksBackgroundColor,
|
||||
cornerRadius: .value(5.0),
|
||||
smoothCorners: true
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: introBackgroundFrame.size
|
||||
)
|
||||
if let introBackgroundView = self.introBackground.view {
|
||||
if introBackgroundView.superview == nil, let firstIconItemView = self.introIconItems[0]?.view {
|
||||
self.scrollView.insertSubview(introBackgroundView, belowSubview: firstIconItemView)
|
||||
}
|
||||
transition.setFrame(view: introBackgroundView, frame: introBackgroundFrame)
|
||||
}
|
||||
contentHeight += introItemsHeight
|
||||
contentHeight += sectionSpacing + 6.0
|
||||
|
||||
let commissionSectionSize = self.commissionSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "COMMISSION",
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "Define the percentage of star revenue your affiliates earn for referring users to your bot.",
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
|
||||
theme: environment.theme,
|
||||
content: .continuous(ListItemSliderSelectorComponent.Continuous(
|
||||
value: 0.0,
|
||||
lowerBoundTitle: "1%",
|
||||
upperBoundTitle: "90%",
|
||||
title: "1%",
|
||||
valueUpdated: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
}
|
||||
))
|
||||
)))
|
||||
],
|
||||
displaySeparators: false
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let commissionSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: commissionSectionSize)
|
||||
if let commissionSectionView = self.commissionSection.view {
|
||||
if commissionSectionView.superview == nil {
|
||||
self.scrollView.addSubview(commissionSectionView)
|
||||
}
|
||||
transition.setFrame(view: commissionSectionView, frame: commissionSectionFrame)
|
||||
}
|
||||
contentHeight += commissionSectionSize.height
|
||||
contentHeight += sectionSpacing + 12.0
|
||||
|
||||
let durationItems: [(months: Int32, title: String, selectedTitle: String)] = [
|
||||
(1, "1m", "1 MONTH"),
|
||||
(3, "3m", "3 MONTHS"),
|
||||
(6, "6m", "6 MONTHS"),
|
||||
(12, "1y", "1 YEAR"),
|
||||
(2 * 12, "2y", "2 YEARS"),
|
||||
(3 * 12, "3y", "3 YEARS"),
|
||||
(Int32.max, "∞", "INDEFINITELY")
|
||||
]
|
||||
let durationSectionSize = self.durationSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "DURATION",
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: durationItems[0].selectedTitle,
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)))
|
||||
], spacing: 4.0, alignment: .alternatingLeftRight)),
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "Set the duration for which affiliates will earn commissions from referred users.",
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
|
||||
theme: environment.theme,
|
||||
content: .discrete(ListItemSliderSelectorComponent.Discrete(
|
||||
values: durationItems.map(\.title),
|
||||
markPositions: true,
|
||||
selectedIndex: 0,
|
||||
title: nil,
|
||||
selectedIndexUpdated: { [weak self] value in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
}
|
||||
))
|
||||
)))
|
||||
],
|
||||
displaySeparators: false
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let durationSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: durationSectionSize)
|
||||
if let durationSectionView = self.durationSection.view {
|
||||
if durationSectionView.superview == nil {
|
||||
self.scrollView.addSubview(durationSectionView)
|
||||
}
|
||||
transition.setFrame(view: durationSectionView, frame: durationSectionFrame)
|
||||
}
|
||||
contentHeight += durationSectionSize.height
|
||||
contentHeight += sectionSpacing + 12.0
|
||||
|
||||
let existingProgramsSectionSize = self.existingProgramsSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: nil,
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "Explore what other mini apps offer.",
|
||||
font: Font.regular(13.0),
|
||||
textColor: environment.theme.list.freeTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "View Existing Programs",
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
accessory: .arrow,
|
||||
action: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = self
|
||||
}
|
||||
)))
|
||||
],
|
||||
displaySeparators: false
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let existingProgramsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: existingProgramsSectionSize)
|
||||
if let existingProgramsSectionView = self.existingProgramsSection.view {
|
||||
if existingProgramsSectionView.superview == nil {
|
||||
self.scrollView.addSubview(existingProgramsSectionView)
|
||||
}
|
||||
transition.setFrame(view: existingProgramsSectionView, frame: existingProgramsSectionFrame)
|
||||
}
|
||||
contentHeight += existingProgramsSectionSize.height
|
||||
contentHeight += sectionSpacing + 12.0
|
||||
|
||||
let endProgramSectionSize = self.endProgramSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
theme: environment.theme,
|
||||
header: nil,
|
||||
footer: nil,
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: "End Affiliate Program",
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemDestructiveColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
], alignment: .center, spacing: 2.0)),
|
||||
accessory: nil,
|
||||
action: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = self
|
||||
}
|
||||
)))
|
||||
],
|
||||
displaySeparators: false
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||
)
|
||||
let endProgramSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: endProgramSectionSize)
|
||||
if let endProgramSectionView = self.endProgramSection.view {
|
||||
if endProgramSectionView.superview == nil {
|
||||
self.scrollView.addSubview(endProgramSectionView)
|
||||
}
|
||||
transition.setFrame(view: endProgramSectionView, frame: endProgramSectionFrame)
|
||||
}
|
||||
contentHeight += endProgramSectionSize.height
|
||||
contentHeight += sectionSpacing
|
||||
|
||||
contentHeight += bottomInset
|
||||
|
||||
let bottomPanelTextSize = self.bottomPanelText.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .markdown(
|
||||
text: "By creating an affiliate program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs.",
|
||||
attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.itemSecondaryTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemAccentColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
)
|
||||
),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 0
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0)
|
||||
)
|
||||
|
||||
let bottomPanelButtonInsets = UIEdgeInsets(top: 10.0, left: sideInset, bottom: 10.0, right: sideInset)
|
||||
|
||||
let bottomPanelButtonSize = self.bottomPanelButton.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
color: environment.theme.list.itemCheckColors.fillColor,
|
||||
foreground: environment.theme.list.itemCheckColors.foregroundColor,
|
||||
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
|
||||
),
|
||||
content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(Text(text: "Start Affiliate Program", font: Font.semibold(17.0), color: environment.theme.list.itemCheckColors.foregroundColor))),
|
||||
isEnabled: true,
|
||||
allowActionWhenDisabled: true,
|
||||
displaysProgress: false,
|
||||
action: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - bottomPanelButtonInsets.left - bottomPanelButtonInsets.right, height: 50.0)
|
||||
)
|
||||
|
||||
let bottomPanelHeight: CGFloat = bottomPanelButtonInsets.top + bottomPanelButtonSize.height + bottomPanelButtonInsets.bottom + bottomPanelTextSize.height + 8.0 + environment.safeInsets.bottom
|
||||
let bottomPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - bottomPanelHeight), size: CGSize(width: availableSize.width, height: bottomPanelHeight))
|
||||
|
||||
let _ = self.bottomPanelBackground.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(BlurredBackgroundComponent(
|
||||
color: environment.theme.rootController.navigationBar.blurredBackgroundColor
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: bottomPanelFrame.size
|
||||
)
|
||||
|
||||
if let bottomPanelBackgroundView = self.bottomPanelBackground.view {
|
||||
if bottomPanelBackgroundView.superview == nil {
|
||||
self.addSubview(bottomPanelBackgroundView)
|
||||
}
|
||||
transition.setFrame(view: bottomPanelBackgroundView, frame: bottomPanelFrame)
|
||||
}
|
||||
transition.setFrame(layer: self.bottomPanelSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: bottomPanelFrame.minY - UIScreenPixel), size: CGSize(width: availableSize.width, height: UIScreenPixel)))
|
||||
|
||||
let bottomPanelButtonFrame = CGRect(origin: CGPoint(x: bottomPanelFrame.minX + bottomPanelButtonInsets.left, y: bottomPanelFrame.minY + bottomPanelButtonInsets.top), size: bottomPanelButtonSize)
|
||||
if let bottomPanelButtonView = self.bottomPanelButton.view {
|
||||
if bottomPanelButtonView.superview == nil {
|
||||
self.addSubview(bottomPanelButtonView)
|
||||
}
|
||||
transition.setFrame(view: bottomPanelButtonView, frame: bottomPanelButtonFrame)
|
||||
}
|
||||
|
||||
let bottomPanelTextFrame = CGRect(origin: CGPoint(x: bottomPanelFrame.minX + floor((bottomPanelFrame.width - bottomPanelTextSize.width) * 0.5), y: bottomPanelButtonFrame.maxY + bottomPanelButtonInsets.bottom), size: bottomPanelTextSize)
|
||||
if let bottomPanelTextView = self.bottomPanelText.view {
|
||||
if bottomPanelTextView.superview == nil {
|
||||
self.addSubview(bottomPanelTextView)
|
||||
}
|
||||
transition.setPosition(view: bottomPanelTextView, position: bottomPanelTextFrame.center)
|
||||
bottomPanelTextView.bounds = CGRect(origin: CGPoint(), size: bottomPanelTextFrame.size)
|
||||
}
|
||||
|
||||
contentHeight += bottomPanelFrame.height
|
||||
|
||||
let contentSize = CGSize(width: availableSize.width, height: contentHeight)
|
||||
if self.scrollView.frame != CGRect(origin: CGPoint(), size: availableSize) {
|
||||
self.scrollView.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||
}
|
||||
if self.scrollView.contentSize != contentSize {
|
||||
self.scrollView.contentSize = contentSize
|
||||
}
|
||||
let scrollInsets = UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: environment.safeInsets.bottom, right: 0.0)
|
||||
if self.scrollView.scrollIndicatorInsets != scrollInsets {
|
||||
self.scrollView.scrollIndicatorInsets = scrollInsets
|
||||
}
|
||||
|
||||
self.updateScrolling(transition: transition)
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
public class AffiliateProgramSetupScreen: ViewControllerComponentContainer {
|
||||
public final class Content: AffiliateProgramSetupScreenInitialData {
|
||||
let peerId: EnginePeer.Id
|
||||
|
||||
init(
|
||||
peerId: EnginePeer.Id
|
||||
) {
|
||||
self.peerId = peerId
|
||||
}
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
private var isDismissed: Bool = false
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
initialContent: Content
|
||||
) {
|
||||
self.context = context
|
||||
|
||||
super.init(context: context, component: AffiliateProgramSetupScreenComponent(
|
||||
context: context,
|
||||
initialContent: initialContent
|
||||
), navigationBarAppearance: .default, theme: .default)
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
guard let self, let componentView = self.node.hostView.componentView as? AffiliateProgramSetupScreenComponent.View else {
|
||||
return
|
||||
}
|
||||
componentView.scrollToTop()
|
||||
}
|
||||
|
||||
self.attemptNavigation = { [weak self] complete in
|
||||
guard let self, let componentView = self.node.hostView.componentView as? AffiliateProgramSetupScreenComponent.View else {
|
||||
return true
|
||||
}
|
||||
|
||||
return componentView.attemptNavigation(complete: complete)
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
}
|
||||
|
||||
public static func content(context: AccountContext, peerId: EnginePeer.Id) -> Signal<AffiliateProgramSetupScreenInitialData, NoError> {
|
||||
return .single(Content(
|
||||
peerId: peerId
|
||||
))
|
||||
}
|
||||
}
|
@ -607,6 +607,7 @@ private final class PeerInfoInteraction {
|
||||
let openWorkingHoursContextMenu: (ASDisplayNode, ContextGesture?) -> Void
|
||||
let openBusinessLocationContextMenu: (ASDisplayNode, ContextGesture?) -> Void
|
||||
let openBirthdayContextMenu: (ASDisplayNode, ContextGesture?) -> Void
|
||||
let editingOpenAffiliateProgram: () -> Void
|
||||
let getController: () -> ViewController?
|
||||
|
||||
init(
|
||||
@ -675,6 +676,7 @@ private final class PeerInfoInteraction {
|
||||
openWorkingHoursContextMenu: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
openBusinessLocationContextMenu: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
openBirthdayContextMenu: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||
editingOpenAffiliateProgram: @escaping () -> Void,
|
||||
getController: @escaping () -> ViewController?
|
||||
) {
|
||||
self.openUsername = openUsername
|
||||
@ -742,6 +744,7 @@ private final class PeerInfoInteraction {
|
||||
self.openWorkingHoursContextMenu = openWorkingHoursContextMenu
|
||||
self.openBusinessLocationContextMenu = openBusinessLocationContextMenu
|
||||
self.openBirthdayContextMenu = openBirthdayContextMenu
|
||||
self.editingOpenAffiliateProgram = editingOpenAffiliateProgram
|
||||
self.getController = getController
|
||||
}
|
||||
}
|
||||
@ -1906,6 +1909,7 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
let ItemInfo = 3
|
||||
let ItemDelete = 4
|
||||
let ItemUsername = 5
|
||||
let ItemAffiliateProgram = 6
|
||||
|
||||
let ItemIntro = 7
|
||||
let ItemCommands = 8
|
||||
@ -1916,6 +1920,10 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemUsername, label: .text("@\(user.addressName ?? "")"), text: presentationData.strings.PeerInfo_Bot_Username, icon: PresentationResourcesSettings.bot, action: {
|
||||
interaction.editingOpenPublicLinkSetup()
|
||||
}))
|
||||
//TODO:localize
|
||||
items[.peerDataSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAffiliateProgram, label: .text("Off"), additionalBadgeLabel: presentationData.strings.Settings_New, text: "Affiliate Program", icon: PresentationResourcesSettings.bot, action: {
|
||||
interaction.editingOpenAffiliateProgram()
|
||||
}))
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenActionItem(id: ItemIntro, text: presentationData.strings.PeerInfo_Bot_EditIntro, icon: UIImage(bundleImageName: "Peer Info/BotIntro"), action: {
|
||||
interaction.openPeerMention("botfather", .withBotStartPayload(ChatControllerInitialBotStart(payload: "\(user.addressName ?? "")-intro", behavior: .interactive)))
|
||||
@ -3012,6 +3020,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
return
|
||||
}
|
||||
self.openBirthdayContextMenu(node: node, gesture: gesture)
|
||||
}, editingOpenAffiliateProgram: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.editingOpenAffiliateProgram()
|
||||
},
|
||||
getController: { [weak self] in
|
||||
return self?.controller
|
||||
@ -8548,6 +8561,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
}
|
||||
|
||||
private func editingOpenAffiliateProgram() {
|
||||
if let peer = self.data?.peer as? TelegramUser, peer.botInfo != nil {
|
||||
let _ = (self.context.sharedContext.makeAffiliateProgramSetupScreenInitialData(context: self.context, peerId: peer.id)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let controller = self.context.sharedContext.makeAffiliateProgramSetupScreen(context: self.context, initialData: initialData)
|
||||
self.controller?.push(controller)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func editingOpenNameColorSetup() {
|
||||
if self.peerId == self.context.account.peerId {
|
||||
let controller = PeerNameColorScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, subject: .account)
|
||||
|
@ -1461,20 +1461,22 @@ final class AutomaticBusinessMessageSetupScreenComponent: Component {
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemSliderSelectorComponent(
|
||||
theme: environment.theme,
|
||||
values: valueList.map { item in
|
||||
return environment.strings.MessageTimer_Days(Int32(item))
|
||||
},
|
||||
markPositions: true,
|
||||
selectedIndex: selectedInactivityIndex,
|
||||
title: nil,
|
||||
selectedIndexUpdated: { [weak self] index in
|
||||
guard let self else {
|
||||
return
|
||||
content: .discrete(ListItemSliderSelectorComponent.Discrete(
|
||||
values: valueList.map { item in
|
||||
return environment.strings.MessageTimer_Days(Int32(item))
|
||||
},
|
||||
markPositions: true,
|
||||
selectedIndex: selectedInactivityIndex,
|
||||
title: nil,
|
||||
selectedIndexUpdated: { [weak self] index in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let index = max(0, min(valueList.count - 1, index))
|
||||
self.inactivityDays = valueList[index]
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
let index = max(0, min(valueList.count - 1, index))
|
||||
self.inactivityDays = valueList[index]
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
))
|
||||
)))
|
||||
]
|
||||
)),
|
||||
|
@ -7,46 +7,80 @@ import LegacyComponents
|
||||
import ComponentFlow
|
||||
|
||||
public final class SliderComponent: Component {
|
||||
public let valueCount: Int
|
||||
public let value: Int
|
||||
public let markPositions: Bool
|
||||
public final class Discrete: Equatable {
|
||||
public let valueCount: Int
|
||||
public let value: Int
|
||||
public let markPositions: Bool
|
||||
public let valueUpdated: (Int) -> Void
|
||||
|
||||
public init(valueCount: Int, value: Int, markPositions: Bool, valueUpdated: @escaping (Int) -> Void) {
|
||||
self.valueCount = valueCount
|
||||
self.value = value
|
||||
self.markPositions = markPositions
|
||||
self.valueUpdated = valueUpdated
|
||||
}
|
||||
|
||||
public static func ==(lhs: Discrete, rhs: Discrete) -> Bool {
|
||||
if lhs.valueCount != rhs.valueCount {
|
||||
return false
|
||||
}
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
if lhs.markPositions != rhs.markPositions {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public final class Continuous: Equatable {
|
||||
public let value: CGFloat
|
||||
public let valueUpdated: (CGFloat) -> Void
|
||||
|
||||
public init(value: CGFloat, valueUpdated: @escaping (CGFloat) -> Void) {
|
||||
self.value = value
|
||||
self.valueUpdated = valueUpdated
|
||||
}
|
||||
|
||||
public static func ==(lhs: Continuous, rhs: Continuous) -> Bool {
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public enum Content: Equatable {
|
||||
case discrete(Discrete)
|
||||
case continuous(Continuous)
|
||||
}
|
||||
|
||||
public let content: Content
|
||||
public let trackBackgroundColor: UIColor
|
||||
public let trackForegroundColor: UIColor
|
||||
public let knobSize: CGFloat?
|
||||
public let knobColor: UIColor?
|
||||
public let valueUpdated: (Int) -> Void
|
||||
public let isTrackingUpdated: ((Bool) -> Void)?
|
||||
|
||||
public init(
|
||||
valueCount: Int,
|
||||
value: Int,
|
||||
markPositions: Bool,
|
||||
content: Content,
|
||||
trackBackgroundColor: UIColor,
|
||||
trackForegroundColor: UIColor,
|
||||
knobSize: CGFloat? = nil,
|
||||
knobColor: UIColor? = nil,
|
||||
valueUpdated: @escaping (Int) -> Void,
|
||||
isTrackingUpdated: ((Bool) -> Void)? = nil
|
||||
) {
|
||||
self.valueCount = valueCount
|
||||
self.value = value
|
||||
self.markPositions = markPositions
|
||||
self.content = content
|
||||
self.trackBackgroundColor = trackBackgroundColor
|
||||
self.trackForegroundColor = trackForegroundColor
|
||||
self.knobSize = knobSize
|
||||
self.knobColor = knobColor
|
||||
self.valueUpdated = valueUpdated
|
||||
self.isTrackingUpdated = isTrackingUpdated
|
||||
}
|
||||
|
||||
public static func ==(lhs: SliderComponent, rhs: SliderComponent) -> Bool {
|
||||
if lhs.valueCount != rhs.valueCount {
|
||||
return false
|
||||
}
|
||||
if lhs.value != rhs.value {
|
||||
return false
|
||||
}
|
||||
if lhs.markPositions != rhs.markPositions {
|
||||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
if lhs.trackBackgroundColor != rhs.trackBackgroundColor {
|
||||
@ -122,10 +156,16 @@ public final class SliderComponent: Component {
|
||||
sliderView.minimumValue = 0.0
|
||||
sliderView.startValue = 0.0
|
||||
sliderView.disablesInteractiveTransitionGestureRecognizer = true
|
||||
sliderView.maximumValue = CGFloat(component.valueCount - 1)
|
||||
sliderView.positionsCount = component.valueCount
|
||||
sliderView.useLinesForPositions = true
|
||||
sliderView.markPositions = component.markPositions
|
||||
|
||||
switch component.content {
|
||||
case let .discrete(discrete):
|
||||
sliderView.maximumValue = CGFloat(discrete.valueCount - 1)
|
||||
sliderView.positionsCount = discrete.valueCount
|
||||
sliderView.useLinesForPositions = true
|
||||
sliderView.markPositions = discrete.markPositions
|
||||
case .continuous:
|
||||
sliderView.maximumValue = 1.0
|
||||
}
|
||||
|
||||
sliderView.backgroundColor = nil
|
||||
sliderView.isOpaque = false
|
||||
@ -162,7 +202,12 @@ public final class SliderComponent: Component {
|
||||
self.sliderView = sliderView
|
||||
self.addSubview(sliderView)
|
||||
}
|
||||
sliderView.value = CGFloat(component.value)
|
||||
switch component.content {
|
||||
case let .discrete(discrete):
|
||||
sliderView.value = CGFloat(discrete.value)
|
||||
case let .continuous(continuous):
|
||||
sliderView.value = continuous.value
|
||||
}
|
||||
sliderView.interactionBegan = {
|
||||
internalIsTrackingUpdated?(true)
|
||||
}
|
||||
@ -180,7 +225,12 @@ public final class SliderComponent: Component {
|
||||
guard let component = self.component, let sliderView = self.sliderView else {
|
||||
return
|
||||
}
|
||||
component.valueUpdated(Int(sliderView.value))
|
||||
switch component.content {
|
||||
case let .discrete(discrete):
|
||||
discrete.valueUpdated(Int(sliderView.value))
|
||||
case let .continuous(continuous):
|
||||
continuous.valueUpdated(sliderView.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ import GiftOptionsScreen
|
||||
import GiftViewScreen
|
||||
import StarsIntroScreen
|
||||
import ContentReportScreen
|
||||
import AffiliateProgramSetupScreen
|
||||
|
||||
private final class AccountUserInterfaceInUseContext {
|
||||
let subscribers = Bag<(Bool) -> Void>()
|
||||
@ -2828,6 +2829,14 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
public func openWebApp(context: AccountContext, parentController: ViewController, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, botPeer: EnginePeer, chatPeer: EnginePeer?, threadId: Int64?, buttonText: String, url: String, simple: Bool, source: ChatOpenWebViewSource, skipTermsOfService: Bool, payload: String?) {
|
||||
openWebAppImpl(context: context, parentController: parentController, updatedPresentationData: updatedPresentationData, botPeer: botPeer, chatPeer: chatPeer, threadId: threadId, buttonText: buttonText, url: url, simple: simple, source: source, skipTermsOfService: skipTermsOfService, payload: payload)
|
||||
}
|
||||
|
||||
public func makeAffiliateProgramSetupScreenInitialData(context: AccountContext, peerId: EnginePeer.Id) -> Signal<AffiliateProgramSetupScreenInitialData, NoError> {
|
||||
return AffiliateProgramSetupScreen.content(context: context, peerId: peerId)
|
||||
}
|
||||
|
||||
public func makeAffiliateProgramSetupScreen(context: AccountContext, initialData: AffiliateProgramSetupScreenInitialData) -> ViewController {
|
||||
return AffiliateProgramSetupScreen(context: context, initialContent: initialData as! AffiliateProgramSetupScreen.Content)
|
||||
}
|
||||
}
|
||||
|
||||
private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {
|
||||
|
Loading…
x
Reference in New Issue
Block a user