Merge commit '51ad5a5efa60aa8e3df243e744f3b47437a1ecd5'

This commit is contained in:
Isaac 2025-11-06 23:17:00 +04:00
commit a05ef5e022
12 changed files with 215 additions and 206 deletions

View File

@ -1547,6 +1547,7 @@ public protocol AccountContext: AnyObject {
var inAppPurchaseManager: InAppPurchaseManager? { get } var inAppPurchaseManager: InAppPurchaseManager? { get }
var starsContext: StarsContext? { get } var starsContext: StarsContext? { get }
var tonContext: StarsContext? { get } var tonContext: StarsContext? { get }
var giftAuctionsManager: GiftAuctionsManager? { get }
var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get } var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get }
var currentContentSettings: Atomic<ContentSettings> { get } var currentContentSettings: Atomic<ContentSettings> { get }

View File

@ -6,7 +6,6 @@ import SwiftSignalKit
import TelegramCore import TelegramCore
import TelegramUIPreferences import TelegramUIPreferences
import TelegramPresentationData import TelegramPresentationData
import LegacyComponents
import ItemListUI import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import ComponentFlow import ComponentFlow
@ -97,7 +96,6 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
private let mediumTextNode: TextNode private let mediumTextNode: TextNode
private let highTextNode: TextNode private let highTextNode: TextNode
private let customTextNode: TextNode private let customTextNode: TextNode
// private var sliderView: TGPhotoEditorSliderView?
private let slider = ComponentView<Empty>() private let slider = ComponentView<Empty>()
private let activateArea: AccessibilityAreaNode private let activateArea: AccessibilityAreaNode
@ -156,76 +154,7 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
// } // }
} }
// func updateSliderView() {
// if let sliderView = self.sliderView, let item = self.item {
// sliderView.maximumValue = 2.0 + (item.customPosition != nil ? 1 : 0)
// sliderView.positionsCount = 3 + (item.customPosition != nil ? 1 : 0)
// var value = item.value.rawValue
// if let customPosition = item.customPosition {
// if case .custom = item.value {
// value = customPosition
// } else {
// if value >= customPosition {
// value += 1
// }
// }
// }
//
// sliderView.value = CGFloat(value)
//
// sliderView.isUserInteractionEnabled = item.enabled
// sliderView.alpha = item.enabled ? 1.0 : 0.4
// sliderView.layer.allowsGroupOpacity = !item.enabled
//
// self.updateAccessibilityLabels()
// }
// }
override func didLoad() {
super.didLoad()
// let sliderView = TGPhotoEditorSliderView()
// sliderView.enablePanHandling = true
// sliderView.trackCornerRadius = 2.0
// sliderView.lineSize = 4.0
// sliderView.dotSize = 5.0
// sliderView.minimumValue = 0.0
// sliderView.maximumValue = 2.0 + (self.item?.customPosition != nil ? 1 : 0)
// sliderView.startValue = 0.0
// sliderView.disablesInteractiveTransitionGestureRecognizer = true
// sliderView.positionsCount = 3 + (self.item?.customPosition != nil ? 1 : 0)
// sliderView.useLinesForPositions = true
// if let item = self.item, let params = self.layoutParams {
// var value = item.value.rawValue
// if let customPosition = item.customPosition {
// if case .custom = item.value {
// value = customPosition
// } else {
// if value >= customPosition {
// value += 1
// }
// }
// }
//
// sliderView.value = CGFloat(value)
// sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor
// sliderView.backColor = item.theme.list.itemSwitchColors.frameColor
// sliderView.startColor = item.theme.list.itemSwitchColors.frameColor
// sliderView.trackColor = item.theme.list.itemAccentColor
// sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme)
//
// sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: 37.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0))
// sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX)
// }
// self.view.addSubview(sliderView)
// sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged)
// self.sliderView = sliderView
//
// self.updateSliderView()
}
func asyncLayout() -> (_ item: AutodownloadDataUsagePickerItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { func asyncLayout() -> (_ item: AutodownloadDataUsagePickerItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
// let currentItem = self.item
let makeLowTextLayout = TextNode.asyncLayout(self.lowTextNode) let makeLowTextLayout = TextNode.asyncLayout(self.lowTextNode)
let makeMediumTextLayout = TextNode.asyncLayout(self.mediumTextNode) let makeMediumTextLayout = TextNode.asyncLayout(self.mediumTextNode)
let makeHighTextLayout = TextNode.asyncLayout(self.highTextNode) let makeHighTextLayout = TextNode.asyncLayout(self.highTextNode)
@ -381,21 +310,11 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
strongSelf.view.addSubview(sliderView) strongSelf.view.addSubview(sliderView)
} }
sliderView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - sliderSize.width) / 2.0), y: 37.0), size: sliderSize) sliderView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - sliderSize.width) / 2.0), y: 37.0), size: sliderSize)
sliderView.isUserInteractionEnabled = item.enabled
sliderView.alpha = item.enabled ? 1.0 : 0.4
sliderView.layer.allowsGroupOpacity = !item.enabled
} }
// if let sliderView = strongSelf.sliderView {
// if themeUpdated {
// sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor
// sliderView.backColor = item.theme.list.itemSwitchColors.frameColor
// sliderView.trackColor = item.theme.list.itemSwitchColors.frameColor
// sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme)
// }
//
// sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: 37.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0))
// sliderView.hitTestEdgeInsets = UIEdgeInsets(top: -sliderView.frame.minX, left: 0.0, bottom: 0.0, right: -sliderView.frame.minX)
//
// strongSelf.updateSliderView()
// }
strongSelf.activateArea.accessibilityLabel = item.strings.AutoDownloadSettings_DataUsage strongSelf.activateArea.accessibilityLabel = item.strings.AutoDownloadSettings_DataUsage
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height)) strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
@ -430,28 +349,5 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
override func animateRemoved(_ currentTimestamp: Double, duration: Double) { override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
// @objc func sliderValueChanged() {
// guard let sliderView = self.sliderView else {
// return
// }
//
// let position = Int(sliderView.value)
// var value: AutomaticDownloadDataUsage?
//
// if let customPosition = self.item?.customPosition {
// if position == customPosition {
// value = .custom
// } else {
// value = AutomaticDownloadDataUsage(rawValue: position > customPosition ? (position - 1) : position)
// }
// } else {
// value = AutomaticDownloadDataUsage(rawValue: position)
// }
//
// if let value = value {
// self.item?.updated(value)
// }
// }
} }

View File

@ -5,10 +5,11 @@ import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import LegacyComponents
import ItemListUI import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import AppBundle import AppBundle
import ComponentFlow
import SliderComponent
class EnergyUsageBatteryLevelItem: ListViewItem, ItemListItem { class EnergyUsageBatteryLevelItem: ListViewItem, ItemListItem {
let systemStyle: ItemListSystemStyle let systemStyle: ItemListSystemStyle
@ -77,11 +78,11 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode {
private let bottomStripeNode: ASDisplayNode private let bottomStripeNode: ASDisplayNode
private let maskNode: ASImageNode private let maskNode: ASImageNode
private var sliderView: TGPhotoEditorSliderView?
private let leftTextNode: ImmediateTextNode private let leftTextNode: ImmediateTextNode
private let rightTextNode: ImmediateTextNode private let rightTextNode: ImmediateTextNode
private let centerTextNode: ImmediateTextNode private let centerTextNode: ImmediateTextNode
private let centerMeasureTextNode: ImmediateTextNode private let centerMeasureTextNode: ImmediateTextNode
private let slider = ComponentView<Empty>()
private let batteryImage: UIImage? private let batteryImage: UIImage?
private let batteryBackgroundNode: ASImageNode private let batteryBackgroundNode: ASImageNode
@ -120,42 +121,8 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode {
self.addSubnode(self.batteryForegroundNode) self.addSubnode(self.batteryForegroundNode)
} }
override func didLoad() {
super.didLoad()
let sliderView = TGPhotoEditorSliderView()
sliderView.enableEdgeTap = true
sliderView.enablePanHandling = true
sliderView.trackCornerRadius = 1.0
sliderView.lineSize = 4.0
sliderView.minimumValue = 0.0
sliderView.startValue = 0.0
sliderView.maximumValue = 1.0
sliderView.disablesInteractiveTransitionGestureRecognizer = true
sliderView.displayEdges = true
if let item = self.item, let params = self.layoutParams {
sliderView.value = rescaleBatteryValueToSlider(CGFloat(item.value) / 100.0)
sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor
sliderView.backColor = item.theme.list.itemSwitchColors.frameColor
sliderView.trackColor = item.theme.list.itemAccentColor
sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme)
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 18.0, y: 36.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 18.0 * 2.0, height: 44.0))
}
self.view.addSubview(sliderView)
sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged)
self.sliderView = sliderView
}
func asyncLayout() -> (_ item: EnergyUsageBatteryLevelItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { func asyncLayout() -> (_ item: EnergyUsageBatteryLevelItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
let currentItem = self.item
return { item, params, neighbors in return { item, params, neighbors in
var themeUpdated = false
if currentItem?.theme !== item.theme {
themeUpdated = true
}
let contentSize: CGSize let contentSize: CGSize
let insets: UIEdgeInsets let insets: UIEdgeInsets
let separatorHeight = UIScreenPixel let separatorHeight = UIScreenPixel
@ -312,15 +279,30 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode {
strongSelf.batteryForegroundNode.frame = strongSelf.batteryBackgroundNode.frame strongSelf.batteryForegroundNode.frame = strongSelf.batteryBackgroundNode.frame
} }
if let sliderView = strongSelf.sliderView { let sliderSize = strongSelf.slider.update(
if themeUpdated { transition: .immediate,
sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor component: AnyComponent(
sliderView.backColor = item.theme.list.itemSecondaryTextColor SliderComponent(
sliderView.trackColor = item.theme.list.itemAccentColor.withAlphaComponent(0.45) content: .continuous(.init(
sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme) value: rescaleBatteryValueToSlider(CGFloat(item.value) / 100.0),
minValue: nil,
valueUpdated: { [weak self] value in
self?.item?.updated(Int32(rescaleSliderToBatteryValue(value) * 100.0))
}
)),
useNative: true,
trackBackgroundColor: item.theme.list.itemSwitchColors.frameColor,
trackForegroundColor: item.theme.list.itemAccentColor
)
),
environment: {},
containerSize: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0)
)
if let sliderView = strongSelf.slider.view {
if sliderView.superview == nil {
strongSelf.view.addSubview(sliderView)
} }
sliderView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - sliderSize.width) / 2.0), y: 36.0 + verticalInset), size: sliderSize)
sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 18.0, y: 36.0 + verticalInset), size: CGSize(width: params.width - params.leftInset - params.rightInset - 18.0 * 2.0, height: 44.0))
} }
} }
}) })
@ -334,12 +316,5 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode {
override func animateRemoved(_ currentTimestamp: Double, duration: Double) { override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
@objc func sliderValueChanged() {
guard let sliderView = self.sliderView else {
return
}
self.item?.updated(Int32(rescaleSliderToBatteryValue(sliderView.value) * 100.0))
}
} }

View File

@ -183,11 +183,14 @@ private final class LocalizationListSearchContainerNode: SearchDisplayController
let foundItems = self.searchQuery.get() let foundItems = self.searchQuery.get()
|> mapToSignal { query -> Signal<[LocalizationInfo]?, NoError> in |> mapToSignal { query -> Signal<[LocalizationInfo]?, NoError> in
if let query = query, !query.isEmpty { if let query = query, !query.isEmpty {
let normalizedQuery = query.lowercased() let normalizedQuery = query.folding(options: [.diacriticInsensitive, .widthInsensitive, .caseInsensitive], locale: nil)
var result: [LocalizationInfo] = [] var result: [LocalizationInfo] = []
var uniqueIds = Set<String>() var uniqueIds = Set<String>()
for info in listState.availableSavedLocalizations + listState.availableOfficialLocalizations { for info in listState.availableSavedLocalizations + listState.availableOfficialLocalizations {
if info.title.lowercased().hasPrefix(normalizedQuery) || info.localizedTitle.lowercased().hasPrefix(normalizedQuery) { let title = info.title.folding(options: [.diacriticInsensitive, .widthInsensitive, .caseInsensitive], locale: nil)
let localizedTitle = info.localizedTitle.folding(options: [.diacriticInsensitive, .widthInsensitive, .caseInsensitive], locale: nil)
if title.hasPrefix(normalizedQuery) || localizedTitle.hasPrefix(normalizedQuery) {
if uniqueIds.contains(info.languageCode) { if uniqueIds.contains(info.languageCode) {
continue continue
} }

View File

@ -56,7 +56,7 @@ public final class GiftAuctionContext {
private let queue: Queue = .mainQueue() private let queue: Queue = .mainQueue()
private let account: Account private let account: Account
private let giftId: Int64 let giftId: Int64
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
@ -73,10 +73,17 @@ public final class GiftAuctionContext {
return self.stateValue.get() return self.stateValue.get()
} }
public init(account: Account, giftId: Int64) { public convenience init(account: Account, giftId: Int64) {
self.init(account: account, giftId: giftId, initialAuctionState: nil, initialMyState: nil)
}
init(account: Account, giftId: Int64, initialAuctionState: State.AuctionState?, initialMyState: State.MyState?) {
self.account = account self.account = account
self.giftId = giftId self.giftId = giftId
self.auctionState = initialAuctionState
self.myState = initialMyState
self.load() self.load()
self.updateAuctionStateDisposable = (self.account.stateManager.updatedStarGiftAuctionState() self.updateAuctionStateDisposable = (self.account.stateManager.updatedStarGiftAuctionState()
@ -265,3 +272,79 @@ func _internal_getGiftAuctionAcquiredGifts(account: Account, giftId: Int64) -> S
} }
} }
} }
func _internal_getActiveGiftAuctions(account: Account, hash: Int64) -> Signal<[GiftAuctionContext]?, NoError> {
return account.network.request(Api.functions.payments.getStarGiftActiveAuctions(hash: hash))
|> retryRequest
|> mapToSignal { result in
return account.postbox.transaction { transaction -> [GiftAuctionContext]? in
switch result {
case let .starGiftActiveAuctions(auctions, users):
let parsedPeers = AccumulatedPeers(users: users)
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
var auctionContexts: [GiftAuctionContext] = []
for auction in auctions {
switch auction {
case let .starGiftActiveAuctionState(giftId, auctionState, userState):
auctionContexts.append(GiftAuctionContext(
account: account,
giftId: giftId,
initialAuctionState: GiftAuctionContext.State.AuctionState(apiAuctionState: auctionState),
initialMyState: GiftAuctionContext.State.MyState(apiAuctionUserState: userState)
))
}
}
return auctionContexts
case .starGiftActiveAuctionsNotModified:
return nil
}
}
}
}
public class GiftAuctionsManager {
private let account: Account
private var auctionContexts: [Int64 : GiftAuctionContext] = [:]
private let disposable = MetaDisposable()
public init(account: Account) {
self.account = account
self.reload()
}
deinit {
self.disposable.dispose()
}
public func reload() {
self.disposable.set((_internal_getActiveGiftAuctions(account: self.account, hash: 0)
|> deliverOnMainQueue).startStrict(next: { [weak self] activeAuctions in
guard let self, let activeAuctions else {
return
}
var auctionContexts: [Int64 : GiftAuctionContext] = [:]
for auction in activeAuctions {
auctionContexts[auction.giftId] = auction
}
self.auctionContexts = auctionContexts
}))
}
public func auctionContextForGift(giftId: Int64) -> GiftAuctionContext {
if let current = self.auctionContexts[giftId] {
return current
} else {
let auctionContext = GiftAuctionContext(account: self.account, giftId: giftId)
self.auctionContexts[giftId] = auctionContext
return auctionContext
}
}
func storeAuctionContext(auctionContext: GiftAuctionContext) {
self.auctionContexts[auctionContext.giftId] = auctionContext
}
}

View File

@ -262,13 +262,16 @@ final class CameraLiveStreamComponent: Component {
public final class StreamAsComponent: Component { public final class StreamAsComponent: Component {
let context: AccountContext let context: AccountContext
let peerId: EnginePeer.Id let peerId: EnginePeer.Id
let isCustomTarget: Bool
public init( public init(
context: AccountContext, context: AccountContext,
peerId: EnginePeer.Id peerId: EnginePeer.Id,
isCustomTarget: Bool
) { ) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
self.isCustomTarget = isCustomTarget
} }
public static func ==(lhs: StreamAsComponent, rhs: StreamAsComponent) -> Bool { public static func ==(lhs: StreamAsComponent, rhs: StreamAsComponent) -> Bool {
@ -278,6 +281,9 @@ public final class StreamAsComponent: Component {
if lhs.peerId != rhs.peerId { if lhs.peerId != rhs.peerId {
return false return false
} }
if lhs.isCustomTarget != rhs.isCustomTarget {
return false
}
return true return true
} }
@ -321,7 +327,8 @@ public final class StreamAsComponent: Component {
}) })
} }
self.avatarNode.frame = CGRect(origin: .zero, size: CGSize(width: 32.0, height: 32.0)) let avatarSize = CGSize(width: 32.0, height: 32.0)
self.avatarNode.frame = CGRect(origin: .zero, size: avatarSize)
if let peer = self.peer { if let peer = self.peer {
self.avatarNode.setPeer( self.avatarNode.setPeer(
context: component.context, context: component.context,
@ -341,7 +348,7 @@ public final class StreamAsComponent: Component {
environment: {}, environment: {},
containerSize: CGSize(width: availableSize.width - 38.0, height: availableSize.height) containerSize: CGSize(width: availableSize.width - 38.0, height: availableSize.height)
) )
let titleFrame = CGRect(origin: CGPoint(x: 42.0, y: 1.0), size: titleSize) let titleFrame = CGRect(origin: CGPoint(x: 42.0, y: component.isCustomTarget ? floorToScreenPixels((avatarSize.height - titleSize.height) / 2.0) : 1.0), size: titleSize)
if let titleView = self.title.view { if let titleView = self.title.view {
if titleView.superview == nil { if titleView.superview == nil {
self.addSubview(titleView) self.addSubview(titleView)
@ -349,29 +356,34 @@ public final class StreamAsComponent: Component {
titleView.frame = titleFrame titleView.frame = titleFrame
} }
let subtitleSize = self.subtitle.update( var maxWidth = titleFrame.maxX
transition: .immediate, if !component.isCustomTarget {
component: AnyComponent( //TODO:localize
MultilineTextComponent( let subtitleSize = self.subtitle.update(
text: .plain(NSAttributedString(string: "change", font: Font.regular(11.0), textColor: UIColor(white: 1.0, alpha: 0.8), paragraphAlignment: .left)) transition: .immediate,
) component: AnyComponent(
), MultilineTextComponent(
environment: {}, text: .plain(NSAttributedString(string: "change", font: Font.regular(11.0), textColor: UIColor(white: 1.0, alpha: 0.8), paragraphAlignment: .left))
containerSize: CGSize(width: availableSize.width - 50.0, height: availableSize.height) )
) ),
let subtitleFrame = CGRect(origin: CGPoint(x: 42.0, y: titleFrame.maxY + 2.0), size: subtitleSize) environment: {},
if let subtitleView = self.subtitle.view { containerSize: CGSize(width: availableSize.width - 50.0, height: availableSize.height)
if subtitleView.superview == nil { )
self.addSubview(subtitleView) let subtitleFrame = CGRect(origin: CGPoint(x: 42.0, y: titleFrame.maxY + 2.0), size: subtitleSize)
if let subtitleView = self.subtitle.view {
if subtitleView.superview == nil {
self.addSubview(subtitleView)
}
subtitleView.frame = subtitleFrame
} }
subtitleView.frame = subtitleFrame
if let icon = self.arrow.image {
self.arrow.frame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + 1.0, y: floorToScreenPixels(subtitleFrame.midY - icon.size.height / 2.0) + 1.0), size: icon.size).insetBy(dx: 1.0, dy: 1.0)
}
maxWidth = max(maxWidth, subtitleFrame.maxX + 16.0)
} }
if let icon = self.arrow.image { return CGSize(width: maxWidth, height: avatarSize.height)
self.arrow.frame = CGRect(origin: CGPoint(x: subtitleFrame.maxX + 1.0, y: floorToScreenPixels(subtitleFrame.midY - icon.size.height / 2.0) + 1.0), size: icon.size).insetBy(dx: 1.0, dy: 1.0)
}
return CGSize(width: max(titleFrame.maxX, subtitleFrame.maxX + 16.0), height: 32.0)
} }
} }

View File

@ -305,6 +305,8 @@ private final class CameraScreenComponent: CombinedComponent {
private var storiesBlockedPeers: BlockedPeersContext? private var storiesBlockedPeers: BlockedPeersContext?
fileprivate var sendAsPeerId: EnginePeer.Id? fileprivate var sendAsPeerId: EnginePeer.Id?
fileprivate var isCustomTarget = false
private var privacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []) private var privacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
private var allowComments = true private var allowComments = true
private var isForwardingDisabled = false private var isForwardingDisabled = false
@ -363,6 +365,13 @@ private final class CameraScreenComponent: CombinedComponent {
Queue.concurrentDefaultQueue().async { Queue.concurrentDefaultQueue().async {
self.setupRecentAssetSubscription() self.setupRecentAssetSubscription()
} }
if let controller = getController() {
if let customTarget = controller.customTarget {
self.sendAsPeerId = customTarget
self.isCustomTarget = true
}
}
} }
deinit { deinit {
@ -943,6 +952,7 @@ private final class CameraScreenComponent: CombinedComponent {
context: self.context, context: self.context,
mode: .create( mode: .create(
sendAsPeerId: self.sendAsPeerId, sendAsPeerId: self.sendAsPeerId,
isCustomTarget: self.isCustomTarget,
privacy: self.privacy, privacy: self.privacy,
allowComments: self.allowComments, allowComments: self.allowComments,
isForwardingDisabled: self.isForwardingDisabled, isForwardingDisabled: self.isForwardingDisabled,
@ -1510,7 +1520,7 @@ private final class CameraScreenComponent: CombinedComponent {
context: component.context, context: component.context,
theme: environment.theme, theme: environment.theme,
strings: environment.strings, strings: environment.strings,
peerId: component.context.account.peerId, peerId: state.sendAsPeerId ?? component.context.account.peerId,
story: state.liveStreamStory, story: state.liveStreamStory,
statusBarHeight: environment.statusBarHeight, statusBarHeight: environment.statusBarHeight,
inputHeight: environment.inputHeight, inputHeight: environment.inputHeight,
@ -1538,13 +1548,18 @@ private final class CameraScreenComponent: CombinedComponent {
let streamAsButton = streamAsButton.update( let streamAsButton = streamAsButton.update(
component: PlainButtonComponent( component: PlainButtonComponent(
content: AnyComponent( content: AnyComponent(
StreamAsComponent(context: component.context, peerId: state.sendAsPeerId ?? component.context.account.peerId) StreamAsComponent(
context: component.context,
peerId: state.sendAsPeerId ?? component.context.account.peerId,
isCustomTarget: state.isCustomTarget
)
), ),
action: { [weak state] in action: { [weak state] in
if let state { if let state {
state.presentStreamAsPeer() state.presentStreamAsPeer()
} }
}, },
isEnabled: !state.isCustomTarget,
animateAlpha: true, animateAlpha: true,
animateScale: false animateScale: false
), ),
@ -3836,6 +3851,7 @@ public class CameraScreenImpl: ViewController, CameraScreen {
private let context: AccountContext private let context: AccountContext
fileprivate let mode: Mode fileprivate let mode: Mode
fileprivate let customTarget: EnginePeer.Id?
fileprivate let holder: CameraHolder? fileprivate let holder: CameraHolder?
fileprivate let transitionIn: TransitionIn? fileprivate let transitionIn: TransitionIn?
fileprivate let transitionOut: (Bool) -> TransitionOut? fileprivate let transitionOut: (Bool) -> TransitionOut?
@ -3901,6 +3917,7 @@ public class CameraScreenImpl: ViewController, CameraScreen {
public init( public init(
context: AccountContext, context: AccountContext,
mode: Mode, mode: Mode,
customTarget: EnginePeer.Id? = nil,
holder: CameraHolder? = nil, holder: CameraHolder? = nil,
transitionIn: TransitionIn?, transitionIn: TransitionIn?,
transitionOut: @escaping (Bool) -> TransitionOut?, transitionOut: @escaping (Bool) -> TransitionOut?,
@ -3908,6 +3925,7 @@ public class CameraScreenImpl: ViewController, CameraScreen {
) { ) {
self.context = context self.context = context
self.mode = mode self.mode = mode
self.customTarget = customTarget
self.holder = holder self.holder = holder
self.transitionIn = transitionIn self.transitionIn = transitionIn
self.transitionOut = transitionOut self.transitionOut = transitionOut

View File

@ -909,8 +909,8 @@ private final class GiftSetupScreenComponent: Component {
self.hideName = true self.hideName = true
} }
if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction) { if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let giftAuctionsManager = component.context.giftAuctionsManager {
let giftAuction = GiftAuctionContext(account: component.context.account, giftId: gift.id) let giftAuction = giftAuctionsManager.auctionContextForGift(giftId: gift.id)
self.giftAuction = giftAuction self.giftAuction = giftAuction
self.giftAuctionDisposable = (giftAuction.state self.giftAuctionDisposable = (giftAuction.state
|> deliverOnMainQueue).start(next: { [weak self] state in |> deliverOnMainQueue).start(next: { [weak self] state in

View File

@ -304,10 +304,10 @@ final class LiveStreamSettingsScreenComponent: Component {
subtitle: subtitle.flatMap { PeerListItemComponent.Subtitle(text: $0, color: .neutral) }, subtitle: subtitle.flatMap { PeerListItemComponent.Subtitle(text: $0, color: .neutral) },
subtitleAccessory: .none, subtitleAccessory: .none,
presence: nil, presence: nil,
rightAccessory: .disclosure, rightAccessory: screenState.isCustomTarget ? .none : .disclosure,
selectionState: .none, selectionState: .none,
hasNext: false, hasNext: false,
action: { [weak self] _, _, _ in action: screenState.isCustomTarget ? nil : { [weak self] _, _, _ in
guard let self else { guard let self else {
return return
} }
@ -316,12 +316,21 @@ final class LiveStreamSettingsScreenComponent: Component {
) )
))] ))]
let streamAsSectionHeader = AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: "START LIVE AS",
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: theme.list.freeTextColor
)),
maximumNumberOfLines: 0
))
let streamAsSectionSize = self.streamAsSection.update( let streamAsSectionSize = self.streamAsSection.update(
transition: transition, transition: transition,
component: AnyComponent(ListSectionComponent( component: AnyComponent(ListSectionComponent(
theme: theme, theme: theme,
style: .glass, style: .glass,
header: nil, header: streamAsSectionHeader,
footer: nil, footer: nil,
items: streamAsSectionItems items: streamAsSectionItems
)), )),
@ -1040,7 +1049,7 @@ final class LiveStreamSettingsScreenComponent: Component {
public class LiveStreamSettingsScreen: ViewControllerComponentContainer { public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
public enum Mode { public enum Mode {
case create(sendAsPeerId: EnginePeer.Id?, privacy: EngineStoryPrivacy, allowComments: Bool, isForwardingDisabled: Bool, pin: Bool, paidMessageStars: Int64) case create(sendAsPeerId: EnginePeer.Id?, isCustomTarget: Bool, privacy: EngineStoryPrivacy, allowComments: Bool, isForwardingDisabled: Bool, pin: Bool, paidMessageStars: Int64)
case edit(PresentationGroupCall) case edit(PresentationGroupCall)
} }
@ -1107,6 +1116,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
var isEdit: Bool var isEdit: Bool
var maxPaidMessageStars: Int64 var maxPaidMessageStars: Int64
var sendAsPeerId: EnginePeer.Id? var sendAsPeerId: EnginePeer.Id?
var isCustomTarget: Bool
var privacy: EngineStoryPrivacy var privacy: EngineStoryPrivacy
var allowComments: Bool var allowComments: Bool
var isForwardingDisabled: Bool var isForwardingDisabled: Bool
@ -1123,6 +1133,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
isEdit: Bool, isEdit: Bool,
maxPaidMessageStars: Int64, maxPaidMessageStars: Int64,
sendAsPeerId: EnginePeer.Id?, sendAsPeerId: EnginePeer.Id?,
isCustomTarget: Bool,
privacy: EngineStoryPrivacy, privacy: EngineStoryPrivacy,
allowComments: Bool, allowComments: Bool,
isForwardingDisabled: Bool, isForwardingDisabled: Bool,
@ -1138,6 +1149,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
self.isEdit = isEdit self.isEdit = isEdit
self.maxPaidMessageStars = maxPaidMessageStars self.maxPaidMessageStars = maxPaidMessageStars
self.sendAsPeerId = sendAsPeerId self.sendAsPeerId = sendAsPeerId
self.isCustomTarget = isCustomTarget
self.privacy = privacy self.privacy = privacy
self.allowComments = allowComments self.allowComments = allowComments
self.isForwardingDisabled = isForwardingDisabled self.isForwardingDisabled = isForwardingDisabled
@ -1353,6 +1365,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
let isEdit: Bool let isEdit: Bool
let maxPaidMessageStars: Int64 = 10000 let maxPaidMessageStars: Int64 = 10000
let sendAsPeerId: EnginePeer.Id? let sendAsPeerId: EnginePeer.Id?
let isCustomTarget: Bool
let privacy: EngineStoryPrivacy let privacy: EngineStoryPrivacy
let allowComments: Bool let allowComments: Bool
let isForwardingDisabled: Bool let isForwardingDisabled: Bool
@ -1362,6 +1375,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
if let current = self.stateValue { if let current = self.stateValue {
isEdit = current.isEdit isEdit = current.isEdit
sendAsPeerId = current.sendAsPeerId sendAsPeerId = current.sendAsPeerId
isCustomTarget = current.isCustomTarget
privacy = current.privacy privacy = current.privacy
allowComments = current.allowComments allowComments = current.allowComments
isForwardingDisabled = current.isForwardingDisabled isForwardingDisabled = current.isForwardingDisabled
@ -1369,9 +1383,10 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
paidMessageStars = current.paidMessageStars paidMessageStars = current.paidMessageStars
} else { } else {
switch mode { switch mode {
case let .create(sendAsPeerIdValue, privacyValue, allowCommentsValue, isForwardingDisabledValue, pinValue, paidMessageStarsValue): case let .create(sendAsPeerIdValue, isCustomTargetValue, privacyValue, allowCommentsValue, isForwardingDisabledValue, pinValue, paidMessageStarsValue):
isEdit = false isEdit = false
sendAsPeerId = sendAsPeerIdValue sendAsPeerId = sendAsPeerIdValue
isCustomTarget = isCustomTargetValue
privacy = privacyValue privacy = privacyValue
allowComments = allowCommentsValue allowComments = allowCommentsValue
isForwardingDisabled = isForwardingDisabledValue isForwardingDisabled = isForwardingDisabledValue
@ -1381,6 +1396,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
let _ = call let _ = call
isEdit = true isEdit = true
sendAsPeerId = nil sendAsPeerId = nil
isCustomTarget = false
privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []) privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
allowComments = true allowComments = true
isForwardingDisabled = false isForwardingDisabled = false
@ -1393,6 +1409,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer {
isEdit: isEdit, isEdit: isEdit,
maxPaidMessageStars: maxPaidMessageStars, maxPaidMessageStars: maxPaidMessageStars,
sendAsPeerId: sendAsPeerId, sendAsPeerId: sendAsPeerId,
isCustomTarget: isCustomTarget,
privacy: privacy, privacy: privacy,
allowComments: allowComments, allowComments: allowComments,
isForwardingDisabled: isForwardingDisabled, isForwardingDisabled: isForwardingDisabled,

View File

@ -2762,7 +2762,7 @@ final class ShareWithPeersScreenComponent: Component {
containerInset += 10.0 containerInset += 10.0
} }
var navigationHeight: CGFloat = 66.0 var navigationHeight: CGFloat = 72.0
let navigationSideInset: CGFloat = 16.0 let navigationSideInset: CGFloat = 16.0
let buttonSideInset: CGFloat = 36.0 let buttonSideInset: CGFloat = 36.0
var navigationButtonsWidth: CGFloat = 0.0 var navigationButtonsWidth: CGFloat = 0.0

View File

@ -128,6 +128,7 @@ public final class AccountContextImpl: AccountContext {
public let inAppPurchaseManager: InAppPurchaseManager? public let inAppPurchaseManager: InAppPurchaseManager?
public let starsContext: StarsContext? public let starsContext: StarsContext?
public let tonContext: StarsContext? public let tonContext: StarsContext?
public let giftAuctionsManager: GiftAuctionsManager?
public let peerChannelMemberCategoriesContextsManager = PeerChannelMemberCategoriesContextsManager() public let peerChannelMemberCategoriesContextsManager = PeerChannelMemberCategoriesContextsManager()
@ -299,6 +300,7 @@ public final class AccountContextImpl: AccountContext {
self.inAppPurchaseManager = InAppPurchaseManager(engine: .authorized(self.engine)) self.inAppPurchaseManager = InAppPurchaseManager(engine: .authorized(self.engine))
self.starsContext = self.engine.payments.peerStarsContext() self.starsContext = self.engine.payments.peerStarsContext()
self.tonContext = self.engine.payments.peerTonContext() self.tonContext = self.engine.payments.peerTonContext()
self.giftAuctionsManager = GiftAuctionsManager(account: account)
} else { } else {
self.prefetchManager = nil self.prefetchManager = nil
self.wallpaperUploadManager = nil self.wallpaperUploadManager = nil
@ -306,6 +308,7 @@ public final class AccountContextImpl: AccountContext {
self.inAppPurchaseManager = nil self.inAppPurchaseManager = nil
self.starsContext = nil self.starsContext = nil
self.tonContext = nil self.tonContext = nil
self.giftAuctionsManager = nil
} }
self.account.stateManager.starsContext = self.starsContext self.account.stateManager.starsContext = self.starsContext

View File

@ -316,6 +316,17 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
transitionOut: nil transitionOut: nil
) )
let mediaEditorCustomTarget = customTarget.flatMap { value -> EnginePeer.Id? in
switch value {
case .myStories:
return nil
case let .peer(id):
return id
case let .botPreview(id, _):
return id
}
}
var presentImpl: ((ViewController) -> Void)? var presentImpl: ((ViewController) -> Void)?
var returnToCameraImpl: (() -> Void)? var returnToCameraImpl: (() -> Void)?
var dismissCameraImpl: (() -> Void)? var dismissCameraImpl: (() -> Void)?
@ -323,6 +334,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
let cameraController = CameraScreenImpl( let cameraController = CameraScreenImpl(
context: context, context: context,
mode: .story, mode: .story,
customTarget: mediaEditorCustomTarget,
transitionIn: transitionIn.flatMap { transitionIn: transitionIn.flatMap {
if let sourceView = $0.sourceView { if let sourceView = $0.sourceView {
return CameraScreenImpl.TransitionIn( return CameraScreenImpl.TransitionIn(
@ -410,17 +422,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
transitionIn = .camera transitionIn = .camera
} }
let mediaEditorCustomTarget = customTarget.flatMap { value -> EnginePeer.Id? in
switch value {
case .myStories:
return nil
case let .peer(id):
return id
case let .botPreview(id, _):
return id
}
}
let controller = MediaEditorScreenImpl( let controller = MediaEditorScreenImpl(
context: context, context: context,
mode: .storyEditor(remainingCount: storyRemainingCount ?? 1), mode: .storyEditor(remainingCount: storyRemainingCount ?? 1),