mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +00:00
Stars ref
This commit is contained in:
parent
2a424340a3
commit
835ea7358b
@ -1104,7 +1104,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makeAffiliateProgramSetupScreenInitialData(context: AccountContext, peerId: EnginePeer.Id, mode: AffiliateProgramSetupScreenMode) -> Signal<AffiliateProgramSetupScreenInitialData, NoError>
|
func makeAffiliateProgramSetupScreenInitialData(context: AccountContext, peerId: EnginePeer.Id, mode: AffiliateProgramSetupScreenMode) -> Signal<AffiliateProgramSetupScreenInitialData, NoError>
|
||||||
func makeAffiliateProgramSetupScreen(context: AccountContext, initialData: AffiliateProgramSetupScreenInitialData) -> ViewController
|
func makeAffiliateProgramSetupScreen(context: AccountContext, initialData: AffiliateProgramSetupScreenInitialData) -> ViewController
|
||||||
|
|
||||||
func makeAffiliateProgramJoinScreen(context: AccountContext, sourcePeer: EnginePeer, commissionPermille: Int32, programDuration: Int32?, mode: JoinAffiliateProgramScreenMode) -> ViewController
|
func makeAffiliateProgramJoinScreen(context: AccountContext, sourcePeer: EnginePeer, commissionPermille: Int32, programDuration: Int32?, revenuePerUser: Double, mode: JoinAffiliateProgramScreenMode) -> ViewController
|
||||||
|
|
||||||
func makeDebugSettingsController(context: AccountContext?) -> ViewController?
|
func makeDebugSettingsController(context: AccountContext?) -> ViewController?
|
||||||
|
|
||||||
|
|||||||
@ -299,7 +299,7 @@ public func peerAvatarImage(postbox: Postbox, network: Network, peerReference: P
|
|||||||
if let cutoutRect {
|
if let cutoutRect {
|
||||||
context.setBlendMode(.copy)
|
context.setBlendMode(.copy)
|
||||||
context.setFillColor(UIColor.clear.cgColor)
|
context.setFillColor(UIColor.clear.cgColor)
|
||||||
context.fillEllipse(in: cutoutRect)
|
context.fillEllipse(in: cutoutRect.offsetBy(dx: 0.0, dy: size.height - cutoutRect.maxY - cutoutRect.height))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let unroundedImage: UIImage?
|
let unroundedImage: UIImage?
|
||||||
|
|||||||
@ -0,0 +1,54 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
public final class TransformContents<ChildEnvironment: Equatable>: CombinedComponent {
|
||||||
|
public typealias EnvironmentType = ChildEnvironment
|
||||||
|
|
||||||
|
private let content: AnyComponent<ChildEnvironment>
|
||||||
|
private let fixedSize: CGSize?
|
||||||
|
private let translation: CGPoint
|
||||||
|
|
||||||
|
public init(content: AnyComponent<ChildEnvironment>, fixedSize: CGSize? = nil, translation: CGPoint) {
|
||||||
|
self.content = content
|
||||||
|
self.fixedSize = fixedSize
|
||||||
|
self.translation = translation
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: TransformContents<ChildEnvironment>, rhs: TransformContents<ChildEnvironment>) -> Bool {
|
||||||
|
if lhs.content != rhs.content {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.fixedSize != rhs.fixedSize {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.translation != rhs.translation {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var body: Body {
|
||||||
|
let child = Child(environment: ChildEnvironment.self)
|
||||||
|
|
||||||
|
return { context in
|
||||||
|
let child = child.update(
|
||||||
|
component: context.component.content,
|
||||||
|
environment: { context.environment[ChildEnvironment.self] },
|
||||||
|
availableSize: context.availableSize,
|
||||||
|
transition: context.transition
|
||||||
|
)
|
||||||
|
|
||||||
|
let size = context.component.fixedSize ?? child.size
|
||||||
|
|
||||||
|
var childFrame = child.size.centered(in: CGRect(origin: CGPoint(), size: size))
|
||||||
|
childFrame.origin.x += context.component.translation.x
|
||||||
|
childFrame.origin.y += context.component.translation.y
|
||||||
|
|
||||||
|
context.add(child
|
||||||
|
.position(childFrame.center)
|
||||||
|
)
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2529,7 +2529,16 @@ open class TextNode: ASDisplayNode, TextNodeProtocol {
|
|||||||
textColor = color
|
textColor = color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let textColor {
|
if image.renderingMode == .alwaysOriginal {
|
||||||
|
let imageRect = CGRect(origin: CGPoint(x: attachment.frame.midX - image.size.width * 0.5, y: attachment.frame.midY - image.size.height * 0.5 + 1.0), size: image.size).offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||||
|
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
||||||
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
|
context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
|
||||||
|
context.draw(image.cgImage!, in: imageRect)
|
||||||
|
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
||||||
|
context.scaleBy(x: 1.0, y: -1.0)
|
||||||
|
context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
|
||||||
|
} else if let textColor {
|
||||||
if let tintedImage = generateTintedImage(image: image, color: textColor) {
|
if let tintedImage = generateTintedImage(image: image, color: textColor) {
|
||||||
let imageRect = CGRect(origin: CGPoint(x: attachment.frame.midX - tintedImage.size.width * 0.5, y: attachment.frame.midY - tintedImage.size.height * 0.5 + 1.0), size: tintedImage.size).offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
let imageRect = CGRect(origin: CGPoint(x: attachment.frame.midX - tintedImage.size.width * 0.5, y: attachment.frame.midY - tintedImage.size.height * 0.5 + 1.0), size: tintedImage.size).offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||||
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
context.translateBy(x: imageRect.midX, y: imageRect.midY)
|
||||||
|
|||||||
@ -798,7 +798,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
|
|
||||||
var useInlineHLS = true
|
var useInlineHLS = true
|
||||||
if let data = context.currentAppConfiguration.with({ $0 }).data {
|
if let data = context.currentAppConfiguration.with({ $0 }).data {
|
||||||
if let value = data["ios_inline_hls"] as? Double {
|
if let value = data["ios_inline_hls_v2"] as? Double {
|
||||||
useInlineHLS = value != 0.0
|
useInlineHLS = value != 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -368,6 +368,7 @@ If you end your affiliate program:
|
|||||||
sourcePeer: bot.peer,
|
sourcePeer: bot.peer,
|
||||||
commissionPermille: bot.commissionPermille,
|
commissionPermille: bot.commissionPermille,
|
||||||
programDuration: bot.durationMonths,
|
programDuration: bot.durationMonths,
|
||||||
|
revenuePerUser: bot.participants == 0 ? 0.0 : Double(bot.revenue) / Double(bot.participants),
|
||||||
mode: .active(JoinAffiliateProgramScreenMode.Active(
|
mode: .active(JoinAffiliateProgramScreenMode.Active(
|
||||||
targetPeer: targetPeer,
|
targetPeer: targetPeer,
|
||||||
bot: bot,
|
bot: bot,
|
||||||
@ -1422,6 +1423,7 @@ If you end your affiliate program:
|
|||||||
sourcePeer: botPeer,
|
sourcePeer: botPeer,
|
||||||
commissionPermille: item.program.commissionPermille,
|
commissionPermille: item.program.commissionPermille,
|
||||||
programDuration: item.program.durationMonths,
|
programDuration: item.program.durationMonths,
|
||||||
|
revenuePerUser: item.program.dailyRevenuePerUser?.totalValue ?? 0.0,
|
||||||
mode: .join(JoinAffiliateProgramScreenMode.Join(
|
mode: .join(JoinAffiliateProgramScreenMode.Join(
|
||||||
initialTargetPeer: targetPeer,
|
initialTargetPeer: targetPeer,
|
||||||
canSelectTargetPeer: false,
|
canSelectTargetPeer: false,
|
||||||
|
|||||||
@ -28,6 +28,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
let sourcePeer: EnginePeer
|
let sourcePeer: EnginePeer
|
||||||
let commissionPermille: Int32
|
let commissionPermille: Int32
|
||||||
let programDuration: Int32?
|
let programDuration: Int32?
|
||||||
|
let revenuePerUser: Double
|
||||||
let mode: JoinAffiliateProgramScreen.Mode
|
let mode: JoinAffiliateProgramScreen.Mode
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -35,12 +36,14 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
sourcePeer: EnginePeer,
|
sourcePeer: EnginePeer,
|
||||||
commissionPermille: Int32,
|
commissionPermille: Int32,
|
||||||
programDuration: Int32?,
|
programDuration: Int32?,
|
||||||
|
revenuePerUser: Double,
|
||||||
mode: JoinAffiliateProgramScreen.Mode
|
mode: JoinAffiliateProgramScreen.Mode
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.sourcePeer = sourcePeer
|
self.sourcePeer = sourcePeer
|
||||||
self.commissionPermille = commissionPermille
|
self.commissionPermille = commissionPermille
|
||||||
self.programDuration = programDuration
|
self.programDuration = programDuration
|
||||||
|
self.revenuePerUser = revenuePerUser
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +89,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
private var toast: ComponentView<Empty>?
|
private var toast: ComponentView<Empty>?
|
||||||
|
|
||||||
private let sourceAvatar = ComponentView<Empty>()
|
private let sourceAvatar = ComponentView<Empty>()
|
||||||
|
private let sourceAvatarBadge = ComponentView<Empty>()
|
||||||
private let targetAvatar = ComponentView<Empty>()
|
private let targetAvatar = ComponentView<Empty>()
|
||||||
private let targetAvatarBadge = ComponentView<Empty>()
|
private let targetAvatarBadge = ComponentView<Empty>()
|
||||||
private let sourceTargetArrow = UIImageView()
|
private let sourceTargetArrow = UIImageView()
|
||||||
@ -96,6 +100,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
|
|
||||||
private let title = ComponentView<Empty>()
|
private let title = ComponentView<Empty>()
|
||||||
private let subtitle = ComponentView<Empty>()
|
private let subtitle = ComponentView<Empty>()
|
||||||
|
private var dailyRevenueText: ComponentView<Empty>?
|
||||||
private let titleTransformContainer: UIView
|
private let titleTransformContainer: UIView
|
||||||
private let bottomPanelContainer: UIView
|
private let bottomPanelContainer: UIView
|
||||||
private let actionButton = ComponentView<Empty>()
|
private let actionButton = ComponentView<Empty>()
|
||||||
@ -128,6 +133,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
private var isChangingTargetPeer: Bool = false
|
private var isChangingTargetPeer: Bool = false
|
||||||
|
|
||||||
private var cachedCloseImage: UIImage?
|
private var cachedCloseImage: UIImage?
|
||||||
|
private var inlineTextStarImage: UIImage?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.bottomOverscrollLimit = 200.0
|
self.bottomOverscrollLimit = 200.0
|
||||||
@ -576,25 +582,71 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
transition.setFrame(view: targetAvatarView, frame: targetAvatarFrame)
|
transition.setFrame(view: targetAvatarView, frame: targetAvatarFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
let badgeIconInset: CGFloat = 2.0
|
if component.revenuePerUser != 0.0 {
|
||||||
let targetAvatarBadgeSize = self.targetAvatarBadge.update(
|
var revenueString = String(format: "%.1f", component.revenuePerUser)
|
||||||
|
if revenueString.hasSuffix(".0") {
|
||||||
|
revenueString = String(revenueString[revenueString.startIndex ..< revenueString.index(revenueString.endIndex, offsetBy: -2)])
|
||||||
|
}
|
||||||
|
let sourceAvatarBadgeSize = self.sourceAvatarBadge.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(BorderedBadgeComponent(
|
component: AnyComponent(BorderedBadgeComponent(
|
||||||
backgroundColor: UIColor(rgb: 0x8A7AFF),
|
backgroundColor: environment.theme.list.itemDisclosureActions.constructive.fillColor,
|
||||||
cutoutColor: environment.theme.list.plainBackgroundColor,
|
cutoutColor: environment.theme.list.plainBackgroundColor,
|
||||||
|
content: AnyComponent(HStack([
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(TransformContents(
|
||||||
content: AnyComponent(BundleIconComponent(
|
content: AnyComponent(BundleIconComponent(
|
||||||
name: "Premium/PremiumStar",
|
name: "Premium/PremiumStar",
|
||||||
tintColor: .white,
|
tintColor: environment.theme.list.itemDisclosureActions.constructive.foregroundColor,
|
||||||
scaleFactor: 0.95
|
scaleFactor: 0.58
|
||||||
)),
|
|
||||||
insets: UIEdgeInsets(top: badgeIconInset, left: badgeIconInset, bottom: badgeIconInset, right: badgeIconInset),
|
|
||||||
aspect: 1.0,
|
|
||||||
cutoutWidth: 1.0 + UIScreenPixel
|
|
||||||
)),
|
)),
|
||||||
|
fixedSize: CGSize(width: 13.0, height: 10.0),
|
||||||
|
translation: CGPoint(x: 0.0, y: 1.0 + UIScreenPixel)
|
||||||
|
))),
|
||||||
|
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: revenueString, font: Font.regular(13.0), textColor: environment.theme.list.itemDisclosureActions.constructive.foregroundColor))
|
||||||
|
)))
|
||||||
|
], spacing: 2.0)),
|
||||||
|
insets: UIEdgeInsets(top: 3.0, left: 6.0, bottom: 3.0, right: 6.0),
|
||||||
|
cutoutWidth: 1.0 + UIScreenPixel)
|
||||||
|
),
|
||||||
environment: {},
|
environment: {},
|
||||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
)
|
)
|
||||||
let targetAvatarBadgeFrame = CGRect(origin: CGPoint(x: targetAvatarFrame.maxX + 3.0 - targetAvatarBadgeSize.width, y: targetAvatarFrame.maxY + 3.0 - targetAvatarBadgeSize.height), size: targetAvatarBadgeSize)
|
let sourceAvatarBadgeFrame = CGRect(origin: CGPoint(x: sourceAvatarFrame.minX + floor((sourceAvatarFrame.width - sourceAvatarBadgeSize.width) * 0.5), y: sourceAvatarFrame.maxY - 7.0 - floor(sourceAvatarBadgeSize.height * 0.5)), size: sourceAvatarBadgeSize)
|
||||||
|
if let sourceAvatarBadgeView = self.sourceAvatarBadge.view {
|
||||||
|
if sourceAvatarBadgeView.superview == nil {
|
||||||
|
self.scrollContentView.addSubview(sourceAvatarBadgeView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: sourceAvatarBadgeView, frame: sourceAvatarBadgeFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetAvatarBadgeSize = self.targetAvatarBadge.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(BorderedBadgeComponent(
|
||||||
|
backgroundColor: environment.theme.list.itemCheckColors.fillColor,
|
||||||
|
cutoutColor: environment.theme.list.plainBackgroundColor,
|
||||||
|
content: AnyComponent(HStack([
|
||||||
|
AnyComponentWithIdentity(id: 0, component: AnyComponent(TransformContents(
|
||||||
|
content: AnyComponent(BundleIconComponent(
|
||||||
|
name: "Media Editor/Link",
|
||||||
|
tintColor: environment.theme.list.itemCheckColors.foregroundColor,
|
||||||
|
scaleFactor: 0.75
|
||||||
|
)),
|
||||||
|
translation: CGPoint(x: 0.0, y: 0.0)
|
||||||
|
))
|
||||||
|
),
|
||||||
|
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(NSAttributedString(string: "\(component.commissionPermille / 10)%", font: Font.regular(13.0), textColor: environment.theme.list.itemCheckColors.foregroundColor))
|
||||||
|
)))
|
||||||
|
], spacing: 2.0)),
|
||||||
|
insets: UIEdgeInsets(top: 3.0, left: 6.0, bottom: 3.0, right: 6.0),
|
||||||
|
cutoutWidth: 1.0 + UIScreenPixel)
|
||||||
|
),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||||
|
)
|
||||||
|
let targetAvatarBadgeFrame = CGRect(origin: CGPoint(x: targetAvatarFrame.minX + floor((targetAvatarFrame.width - targetAvatarBadgeSize.width) * 0.5), y: targetAvatarFrame.maxY - 7.0 - floor(targetAvatarBadgeSize.height * 0.5)), size: targetAvatarBadgeSize)
|
||||||
if let targetAvatarBadgeView = self.targetAvatarBadge.view {
|
if let targetAvatarBadgeView = self.targetAvatarBadge.view {
|
||||||
if targetAvatarBadgeView.superview == nil {
|
if targetAvatarBadgeView.superview == nil {
|
||||||
self.scrollContentView.addSubview(targetAvatarBadgeView)
|
self.scrollContentView.addSubview(targetAvatarBadgeView)
|
||||||
@ -723,12 +775,22 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let titleString: String
|
let titleString: String
|
||||||
let subtitleString: String
|
var subtitleString: String
|
||||||
|
var dailyRevenueString: String?
|
||||||
let termsString: String
|
let termsString: String
|
||||||
switch currentMode {
|
switch currentMode {
|
||||||
case .join:
|
case .join:
|
||||||
titleString = "Affiliate Program"
|
titleString = "Affiliate Program"
|
||||||
subtitleString = "**\(component.sourcePeer.compactDisplayTitle)** will share **\(commissionTitle)** of the revenue from each user you refer to it for **\(durationTitle)**."
|
subtitleString = "**\(component.sourcePeer.compactDisplayTitle)** will share **\(commissionTitle)** of the revenue from each user you refer to it for **\(durationTitle)**."
|
||||||
|
|
||||||
|
if component.revenuePerUser != 0.0 {
|
||||||
|
var revenueString = String(format: "%.1f", component.revenuePerUser)
|
||||||
|
if revenueString.hasSuffix(".0") {
|
||||||
|
revenueString = String(revenueString[revenueString.startIndex ..< revenueString.index(revenueString.endIndex, offsetBy: -2)])
|
||||||
|
}
|
||||||
|
dailyRevenueString = "Daily revenue per user: #**\(revenueString)**"
|
||||||
|
}
|
||||||
|
|
||||||
termsString = "By joining this program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs."
|
termsString = "By joining this program, you afree to the [terms and conditions](https://telegram.org/terms) of Affiliate Programs."
|
||||||
case let .active(active):
|
case let .active(active):
|
||||||
titleString = "Referral Link"
|
titleString = "Referral Link"
|
||||||
@ -799,7 +861,115 @@ private final class JoinAffiliateProgramScreenComponent: Component {
|
|||||||
transition.setPosition(view: subtitleView, position: subtitleFrame.center)
|
transition.setPosition(view: subtitleView, position: subtitleFrame.center)
|
||||||
subtitleView.bounds = CGRect(origin: CGPoint(), size: subtitleFrame.size)
|
subtitleView.bounds = CGRect(origin: CGPoint(), size: subtitleFrame.size)
|
||||||
}
|
}
|
||||||
contentHeight += subtitleSize.height + 23.0
|
contentHeight += subtitleSize.height
|
||||||
|
|
||||||
|
if let dailyRevenueString {
|
||||||
|
let dailyRevenueText: ComponentView<Empty>
|
||||||
|
if let current = self.dailyRevenueText {
|
||||||
|
dailyRevenueText = current
|
||||||
|
} else {
|
||||||
|
dailyRevenueText = ComponentView()
|
||||||
|
self.dailyRevenueText = dailyRevenueText
|
||||||
|
}
|
||||||
|
|
||||||
|
var inlineTextStarImage: UIImage?
|
||||||
|
if let current = self.inlineTextStarImage {
|
||||||
|
inlineTextStarImage = current
|
||||||
|
} else {
|
||||||
|
if let image = UIImage(bundleImageName: "Premium/Stars/StarSmall") {
|
||||||
|
let starInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
|
||||||
|
inlineTextStarImage = generateImage(CGSize(width: starInsets.left + image.size.width + starInsets.right, height: image.size.height), rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
UIGraphicsPushContext(context)
|
||||||
|
defer {
|
||||||
|
UIGraphicsPopContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
image.draw(at: CGPoint(x: starInsets.left, y: starInsets.top))
|
||||||
|
})?.withRenderingMode(.alwaysOriginal)
|
||||||
|
self.inlineTextStarImage = inlineTextStarImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributedDailyRevenueString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(dailyRevenueString, attributes: MarkdownAttributes(
|
||||||
|
body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor),
|
||||||
|
bold: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: environment.theme.list.itemPrimaryTextColor),
|
||||||
|
link: MarkdownAttributeSet(font: Font.regular(15.0), textColor: environment.theme.list.itemAccentColor),
|
||||||
|
linkAttribute: { url in
|
||||||
|
return ("URL", url)
|
||||||
|
}
|
||||||
|
), textAlignment: .center))
|
||||||
|
if let range = attributedDailyRevenueString.string.range(of: "#"), let starImage = inlineTextStarImage {
|
||||||
|
final class RunDelegateData {
|
||||||
|
let ascent: CGFloat
|
||||||
|
let descent: CGFloat
|
||||||
|
let width: CGFloat
|
||||||
|
|
||||||
|
init(ascent: CGFloat, descent: CGFloat, width: CGFloat) {
|
||||||
|
self.ascent = ascent
|
||||||
|
self.descent = descent
|
||||||
|
self.width = width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let runDelegateData = RunDelegateData(
|
||||||
|
ascent: Font.regular(15.0).ascender,
|
||||||
|
descent: Font.regular(15.0).descender,
|
||||||
|
width: starImage.size.width + 2.0
|
||||||
|
)
|
||||||
|
var callbacks = CTRunDelegateCallbacks(
|
||||||
|
version: kCTRunDelegateCurrentVersion,
|
||||||
|
dealloc: { dataRef in
|
||||||
|
Unmanaged<RunDelegateData>.fromOpaque(dataRef).release()
|
||||||
|
},
|
||||||
|
getAscent: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().ascent
|
||||||
|
},
|
||||||
|
getDescent: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().descent
|
||||||
|
},
|
||||||
|
getWidth: { dataRef in
|
||||||
|
let data = Unmanaged<RunDelegateData>.fromOpaque(dataRef)
|
||||||
|
return data.takeUnretainedValue().width
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if let runDelegate = CTRunDelegateCreate(&callbacks, Unmanaged.passRetained(runDelegateData).toOpaque()) {
|
||||||
|
attributedDailyRevenueString.addAttribute(NSAttributedString.Key(kCTRunDelegateAttributeName as String), value: runDelegate, range: NSRange(range, in: attributedDailyRevenueString.string))
|
||||||
|
}
|
||||||
|
attributedDailyRevenueString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: attributedDailyRevenueString.string))
|
||||||
|
attributedDailyRevenueString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xffffff), range: NSRange(range, in: attributedDailyRevenueString.string))
|
||||||
|
attributedDailyRevenueString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedDailyRevenueString.string))
|
||||||
|
}
|
||||||
|
|
||||||
|
let dailyRevenueTextSize = dailyRevenueText.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(MultilineTextComponent(
|
||||||
|
text: .plain(attributedDailyRevenueString),
|
||||||
|
horizontalAlignment: .center,
|
||||||
|
maximumNumberOfLines: 0,
|
||||||
|
lineSpacing: 0.2
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
|
||||||
|
)
|
||||||
|
contentHeight += 16.0
|
||||||
|
let dailyRevenueTextFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - dailyRevenueTextSize.width) * 0.5), y: contentHeight), size: dailyRevenueTextSize)
|
||||||
|
if let dailyRevenueTextView = dailyRevenueText.view {
|
||||||
|
if dailyRevenueTextView.superview == nil {
|
||||||
|
self.scrollContentView.addSubview(dailyRevenueTextView)
|
||||||
|
}
|
||||||
|
transition.setPosition(view: dailyRevenueTextView, position: dailyRevenueTextFrame.center)
|
||||||
|
dailyRevenueTextView.bounds = CGRect(origin: CGPoint(), size: dailyRevenueTextFrame.size)
|
||||||
|
}
|
||||||
|
contentHeight += dailyRevenueTextSize.height
|
||||||
|
} else if let dailyRevenueText = self.dailyRevenueText {
|
||||||
|
self.dailyRevenueText = nil
|
||||||
|
dailyRevenueText.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
contentHeight += 23.0
|
||||||
|
|
||||||
var displayTargetPeer = false
|
var displayTargetPeer = false
|
||||||
var isTargetPeerSelectable = false
|
var isTargetPeerSelectable = false
|
||||||
@ -1116,6 +1286,7 @@ public class JoinAffiliateProgramScreen: ViewControllerComponentContainer {
|
|||||||
sourcePeer: EnginePeer,
|
sourcePeer: EnginePeer,
|
||||||
commissionPermille: Int32,
|
commissionPermille: Int32,
|
||||||
programDuration: Int32?,
|
programDuration: Int32?,
|
||||||
|
revenuePerUser: Double,
|
||||||
mode: Mode
|
mode: Mode
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -1125,6 +1296,7 @@ public class JoinAffiliateProgramScreen: ViewControllerComponentContainer {
|
|||||||
sourcePeer: sourcePeer,
|
sourcePeer: sourcePeer,
|
||||||
commissionPermille: commissionPermille,
|
commissionPermille: commissionPermille,
|
||||||
programDuration: programDuration,
|
programDuration: programDuration,
|
||||||
|
revenuePerUser: revenuePerUser,
|
||||||
mode: mode
|
mode: mode
|
||||||
), navigationBarAppearance: .none)
|
), navigationBarAppearance: .none)
|
||||||
|
|
||||||
|
|||||||
@ -8685,6 +8685,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
sourcePeer: bot.peer,
|
sourcePeer: bot.peer,
|
||||||
commissionPermille: bot.commissionPermille,
|
commissionPermille: bot.commissionPermille,
|
||||||
programDuration: bot.durationMonths,
|
programDuration: bot.durationMonths,
|
||||||
|
revenuePerUser: bot.participants == 0 ? 0.0 : Double(bot.revenue) / Double(bot.participants),
|
||||||
mode: .active(JoinAffiliateProgramScreenMode.Active(
|
mode: .active(JoinAffiliateProgramScreenMode.Active(
|
||||||
targetPeer: targetPeer,
|
targetPeer: targetPeer,
|
||||||
bot: bot,
|
bot: bot,
|
||||||
@ -8707,6 +8708,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
sourcePeer: .user(peer),
|
sourcePeer: .user(peer),
|
||||||
commissionPermille: starRefProgram.commissionPermille,
|
commissionPermille: starRefProgram.commissionPermille,
|
||||||
programDuration: starRefProgram.durationMonths,
|
programDuration: starRefProgram.durationMonths,
|
||||||
|
revenuePerUser: starRefProgram.dailyRevenuePerUser?.totalValue ?? 0.0,
|
||||||
mode: mode
|
mode: mode
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2840,8 +2840,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return AffiliateProgramSetupScreen(context: context, initialContent: initialData)
|
return AffiliateProgramSetupScreen(context: context, initialContent: initialData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeAffiliateProgramJoinScreen(context: AccountContext, sourcePeer: EnginePeer, commissionPermille: Int32, programDuration: Int32?, mode: JoinAffiliateProgramScreenMode) -> ViewController {
|
public func makeAffiliateProgramJoinScreen(context: AccountContext, sourcePeer: EnginePeer, commissionPermille: Int32, programDuration: Int32?, revenuePerUser: Double, mode: JoinAffiliateProgramScreenMode) -> ViewController {
|
||||||
return JoinAffiliateProgramScreen(context: context, sourcePeer: sourcePeer, commissionPermille: commissionPermille, programDuration: programDuration, mode: mode)
|
return JoinAffiliateProgramScreen(context: context, sourcePeer: sourcePeer, commissionPermille: commissionPermille, programDuration: programDuration, revenuePerUser: revenuePerUser, mode: mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user