diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 77601c708a..7564a61896 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1547,6 +1547,7 @@ public protocol AccountContext: AnyObject { var inAppPurchaseManager: InAppPurchaseManager? { get } var starsContext: StarsContext? { get } var tonContext: StarsContext? { get } + var giftAuctionsManager: GiftAuctionsManager? { get } var currentLimitsConfiguration: Atomic { get } var currentContentSettings: Atomic { get } diff --git a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift index 7c46d31f06..735565cf31 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/AutodownloadDataUsagePickerItem.swift @@ -6,7 +6,6 @@ import SwiftSignalKit import TelegramCore import TelegramUIPreferences import TelegramPresentationData -import LegacyComponents import ItemListUI import PresentationDataUtils import ComponentFlow @@ -97,7 +96,6 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { private let mediumTextNode: TextNode private let highTextNode: TextNode private let customTextNode: TextNode -// private var sliderView: TGPhotoEditorSliderView? private let slider = ComponentView() 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) { -// let currentItem = self.item let makeLowTextLayout = TextNode.asyncLayout(self.lowTextNode) let makeMediumTextLayout = TextNode.asyncLayout(self.mediumTextNode) let makeHighTextLayout = TextNode.asyncLayout(self.highTextNode) @@ -381,21 +310,11 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode { strongSelf.view.addSubview(sliderView) } 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.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) { 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) -// } -// } } diff --git a/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift b/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift index 537dc09ae5..84ce6fb2ae 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift @@ -5,10 +5,11 @@ import AsyncDisplayKit import SwiftSignalKit import TelegramCore import TelegramPresentationData -import LegacyComponents import ItemListUI import PresentationDataUtils import AppBundle +import ComponentFlow +import SliderComponent class EnergyUsageBatteryLevelItem: ListViewItem, ItemListItem { let systemStyle: ItemListSystemStyle @@ -77,11 +78,11 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { private let bottomStripeNode: ASDisplayNode private let maskNode: ASImageNode - private var sliderView: TGPhotoEditorSliderView? private let leftTextNode: ImmediateTextNode private let rightTextNode: ImmediateTextNode private let centerTextNode: ImmediateTextNode private let centerMeasureTextNode: ImmediateTextNode + private let slider = ComponentView() private let batteryImage: UIImage? private let batteryBackgroundNode: ASImageNode @@ -119,43 +120,9 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { self.addSubnode(self.batteryBackgroundNode) 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) { - let currentItem = self.item - return { item, params, neighbors in - var themeUpdated = false - if currentItem?.theme !== item.theme { - themeUpdated = true - } - let contentSize: CGSize let insets: UIEdgeInsets let separatorHeight = UIScreenPixel @@ -312,15 +279,30 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { strongSelf.batteryForegroundNode.frame = strongSelf.batteryBackgroundNode.frame } - if let sliderView = strongSelf.sliderView { - if themeUpdated { - sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor - sliderView.backColor = item.theme.list.itemSecondaryTextColor - sliderView.trackColor = item.theme.list.itemAccentColor.withAlphaComponent(0.45) - sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme) + let sliderSize = strongSelf.slider.update( + transition: .immediate, + component: AnyComponent( + SliderComponent( + content: .continuous(.init( + 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: params.leftInset + 18.0, y: 36.0 + verticalInset), size: CGSize(width: params.width - params.leftInset - params.rightInset - 18.0 * 2.0, height: 44.0)) + sliderView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((params.width - sliderSize.width) / 2.0), y: 36.0 + verticalInset), size: sliderSize) } } }) @@ -334,12 +316,5 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { override func animateRemoved(_ currentTimestamp: Double, duration: Double) { 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)) - } } diff --git a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift index 0f79fad0ca..4651de00b9 100644 --- a/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift +++ b/submodules/SettingsUI/Sources/Language Selection/LocalizationListControllerNode.swift @@ -183,11 +183,14 @@ private final class LocalizationListSearchContainerNode: SearchDisplayController let foundItems = self.searchQuery.get() |> mapToSignal { query -> Signal<[LocalizationInfo]?, NoError> in if let query = query, !query.isEmpty { - let normalizedQuery = query.lowercased() + let normalizedQuery = query.folding(options: [.diacriticInsensitive, .widthInsensitive, .caseInsensitive], locale: nil) var result: [LocalizationInfo] = [] var uniqueIds = Set() 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) { continue } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift index fdb923c700..765ff5aa4c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift @@ -56,7 +56,7 @@ public final class GiftAuctionContext { private let queue: Queue = .mainQueue() private let account: Account - private let giftId: Int64 + let giftId: Int64 private let disposable = MetaDisposable() @@ -73,10 +73,17 @@ public final class GiftAuctionContext { 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.giftId = giftId + self.auctionState = initialAuctionState + self.myState = initialMyState + self.load() 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 + } +} diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraLiveStreamComponent.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraLiveStreamComponent.swift index c573aa26bf..883878836f 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraLiveStreamComponent.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraLiveStreamComponent.swift @@ -262,13 +262,16 @@ final class CameraLiveStreamComponent: Component { public final class StreamAsComponent: Component { let context: AccountContext let peerId: EnginePeer.Id + let isCustomTarget: Bool public init( context: AccountContext, - peerId: EnginePeer.Id + peerId: EnginePeer.Id, + isCustomTarget: Bool ) { self.context = context self.peerId = peerId + self.isCustomTarget = isCustomTarget } public static func ==(lhs: StreamAsComponent, rhs: StreamAsComponent) -> Bool { @@ -278,6 +281,9 @@ public final class StreamAsComponent: Component { if lhs.peerId != rhs.peerId { return false } + if lhs.isCustomTarget != rhs.isCustomTarget { + return false + } 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 { self.avatarNode.setPeer( context: component.context, @@ -341,7 +348,7 @@ public final class StreamAsComponent: Component { environment: {}, 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 titleView.superview == nil { self.addSubview(titleView) @@ -349,29 +356,34 @@ public final class StreamAsComponent: Component { titleView.frame = titleFrame } - let subtitleSize = self.subtitle.update( - transition: .immediate, - component: AnyComponent( - MultilineTextComponent( - text: .plain(NSAttributedString(string: "change", font: Font.regular(11.0), textColor: UIColor(white: 1.0, alpha: 0.8), paragraphAlignment: .left)) - ) - ), - environment: {}, - 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) - if let subtitleView = self.subtitle.view { - if subtitleView.superview == nil { - self.addSubview(subtitleView) + var maxWidth = titleFrame.maxX + if !component.isCustomTarget { + //TODO:localize + let subtitleSize = self.subtitle.update( + transition: .immediate, + component: AnyComponent( + MultilineTextComponent( + text: .plain(NSAttributedString(string: "change", font: Font.regular(11.0), textColor: UIColor(white: 1.0, alpha: 0.8), paragraphAlignment: .left)) + ) + ), + environment: {}, + 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) + 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 { - 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) + return CGSize(width: maxWidth, height: avatarSize.height) } } diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift index 2cd076b905..b4996b8b2f 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift @@ -305,6 +305,8 @@ private final class CameraScreenComponent: CombinedComponent { private var storiesBlockedPeers: BlockedPeersContext? fileprivate var sendAsPeerId: EnginePeer.Id? + fileprivate var isCustomTarget = false + private var privacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []) private var allowComments = true private var isForwardingDisabled = false @@ -363,6 +365,13 @@ private final class CameraScreenComponent: CombinedComponent { Queue.concurrentDefaultQueue().async { self.setupRecentAssetSubscription() } + + if let controller = getController() { + if let customTarget = controller.customTarget { + self.sendAsPeerId = customTarget + self.isCustomTarget = true + } + } } deinit { @@ -943,6 +952,7 @@ private final class CameraScreenComponent: CombinedComponent { context: self.context, mode: .create( sendAsPeerId: self.sendAsPeerId, + isCustomTarget: self.isCustomTarget, privacy: self.privacy, allowComments: self.allowComments, isForwardingDisabled: self.isForwardingDisabled, @@ -1510,7 +1520,7 @@ private final class CameraScreenComponent: CombinedComponent { context: component.context, theme: environment.theme, strings: environment.strings, - peerId: component.context.account.peerId, + peerId: state.sendAsPeerId ?? component.context.account.peerId, story: state.liveStreamStory, statusBarHeight: environment.statusBarHeight, inputHeight: environment.inputHeight, @@ -1538,13 +1548,18 @@ private final class CameraScreenComponent: CombinedComponent { let streamAsButton = streamAsButton.update( component: PlainButtonComponent( 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 if let state { state.presentStreamAsPeer() } }, + isEnabled: !state.isCustomTarget, animateAlpha: true, animateScale: false ), @@ -3836,6 +3851,7 @@ public class CameraScreenImpl: ViewController, CameraScreen { private let context: AccountContext fileprivate let mode: Mode + fileprivate let customTarget: EnginePeer.Id? fileprivate let holder: CameraHolder? fileprivate let transitionIn: TransitionIn? fileprivate let transitionOut: (Bool) -> TransitionOut? @@ -3901,6 +3917,7 @@ public class CameraScreenImpl: ViewController, CameraScreen { public init( context: AccountContext, mode: Mode, + customTarget: EnginePeer.Id? = nil, holder: CameraHolder? = nil, transitionIn: TransitionIn?, transitionOut: @escaping (Bool) -> TransitionOut?, @@ -3908,6 +3925,7 @@ public class CameraScreenImpl: ViewController, CameraScreen { ) { self.context = context self.mode = mode + self.customTarget = customTarget self.holder = holder self.transitionIn = transitionIn self.transitionOut = transitionOut diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index 58a2cbf639..4610164102 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -909,8 +909,8 @@ private final class GiftSetupScreenComponent: Component { self.hideName = true } - if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction) { - let giftAuction = GiftAuctionContext(account: component.context.account, giftId: gift.id) + if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let giftAuctionsManager = component.context.giftAuctionsManager { + let giftAuction = giftAuctionsManager.auctionContextForGift(giftId: gift.id) self.giftAuction = giftAuction self.giftAuctionDisposable = (giftAuction.state |> deliverOnMainQueue).start(next: { [weak self] state in diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/LiveStreamSettingsScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/LiveStreamSettingsScreen.swift index 87d8462063..e616f6feba 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/LiveStreamSettingsScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/LiveStreamSettingsScreen.swift @@ -304,10 +304,10 @@ final class LiveStreamSettingsScreenComponent: Component { subtitle: subtitle.flatMap { PeerListItemComponent.Subtitle(text: $0, color: .neutral) }, subtitleAccessory: .none, presence: nil, - rightAccessory: .disclosure, + rightAccessory: screenState.isCustomTarget ? .none : .disclosure, selectionState: .none, hasNext: false, - action: { [weak self] _, _, _ in + action: screenState.isCustomTarget ? nil : { [weak self] _, _, _ in guard let self else { 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( transition: transition, component: AnyComponent(ListSectionComponent( theme: theme, style: .glass, - header: nil, + header: streamAsSectionHeader, footer: nil, items: streamAsSectionItems )), @@ -1040,7 +1049,7 @@ final class LiveStreamSettingsScreenComponent: Component { public class LiveStreamSettingsScreen: ViewControllerComponentContainer { 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) } @@ -1107,6 +1116,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { var isEdit: Bool var maxPaidMessageStars: Int64 var sendAsPeerId: EnginePeer.Id? + var isCustomTarget: Bool var privacy: EngineStoryPrivacy var allowComments: Bool var isForwardingDisabled: Bool @@ -1123,6 +1133,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { isEdit: Bool, maxPaidMessageStars: Int64, sendAsPeerId: EnginePeer.Id?, + isCustomTarget: Bool, privacy: EngineStoryPrivacy, allowComments: Bool, isForwardingDisabled: Bool, @@ -1138,6 +1149,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { self.isEdit = isEdit self.maxPaidMessageStars = maxPaidMessageStars self.sendAsPeerId = sendAsPeerId + self.isCustomTarget = isCustomTarget self.privacy = privacy self.allowComments = allowComments self.isForwardingDisabled = isForwardingDisabled @@ -1353,6 +1365,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { let isEdit: Bool let maxPaidMessageStars: Int64 = 10000 let sendAsPeerId: EnginePeer.Id? + let isCustomTarget: Bool let privacy: EngineStoryPrivacy let allowComments: Bool let isForwardingDisabled: Bool @@ -1362,6 +1375,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { if let current = self.stateValue { isEdit = current.isEdit sendAsPeerId = current.sendAsPeerId + isCustomTarget = current.isCustomTarget privacy = current.privacy allowComments = current.allowComments isForwardingDisabled = current.isForwardingDisabled @@ -1369,9 +1383,10 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { paidMessageStars = current.paidMessageStars } else { switch mode { - case let .create(sendAsPeerIdValue, privacyValue, allowCommentsValue, isForwardingDisabledValue, pinValue, paidMessageStarsValue): + case let .create(sendAsPeerIdValue, isCustomTargetValue, privacyValue, allowCommentsValue, isForwardingDisabledValue, pinValue, paidMessageStarsValue): isEdit = false sendAsPeerId = sendAsPeerIdValue + isCustomTarget = isCustomTargetValue privacy = privacyValue allowComments = allowCommentsValue isForwardingDisabled = isForwardingDisabledValue @@ -1381,6 +1396,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { let _ = call isEdit = true sendAsPeerId = nil + isCustomTarget = false privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []) allowComments = true isForwardingDisabled = false @@ -1393,6 +1409,7 @@ public class LiveStreamSettingsScreen: ViewControllerComponentContainer { isEdit: isEdit, maxPaidMessageStars: maxPaidMessageStars, sendAsPeerId: sendAsPeerId, + isCustomTarget: isCustomTarget, privacy: privacy, allowComments: allowComments, isForwardingDisabled: isForwardingDisabled, diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index bf2f16740c..7295da3847 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -2762,7 +2762,7 @@ final class ShareWithPeersScreenComponent: Component { containerInset += 10.0 } - var navigationHeight: CGFloat = 66.0 + var navigationHeight: CGFloat = 72.0 let navigationSideInset: CGFloat = 16.0 let buttonSideInset: CGFloat = 36.0 var navigationButtonsWidth: CGFloat = 0.0 diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index 5a349abea3..eca7ccd52f 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -128,6 +128,7 @@ public final class AccountContextImpl: AccountContext { public let inAppPurchaseManager: InAppPurchaseManager? public let starsContext: StarsContext? public let tonContext: StarsContext? + public let giftAuctionsManager: GiftAuctionsManager? public let peerChannelMemberCategoriesContextsManager = PeerChannelMemberCategoriesContextsManager() @@ -299,6 +300,7 @@ public final class AccountContextImpl: AccountContext { self.inAppPurchaseManager = InAppPurchaseManager(engine: .authorized(self.engine)) self.starsContext = self.engine.payments.peerStarsContext() self.tonContext = self.engine.payments.peerTonContext() + self.giftAuctionsManager = GiftAuctionsManager(account: account) } else { self.prefetchManager = nil self.wallpaperUploadManager = nil @@ -306,6 +308,7 @@ public final class AccountContextImpl: AccountContext { self.inAppPurchaseManager = nil self.starsContext = nil self.tonContext = nil + self.giftAuctionsManager = nil } self.account.stateManager.starsContext = self.starsContext diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 03a5bb7d8f..797fce2cbd 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -316,6 +316,17 @@ public final class TelegramRootController: NavigationController, TelegramRootCon 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 returnToCameraImpl: (() -> Void)? var dismissCameraImpl: (() -> Void)? @@ -323,6 +334,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon let cameraController = CameraScreenImpl( context: context, mode: .story, + customTarget: mediaEditorCustomTarget, transitionIn: transitionIn.flatMap { if let sourceView = $0.sourceView { return CameraScreenImpl.TransitionIn( @@ -410,17 +422,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon 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( context: context, mode: .storyEditor(remainingCount: storyRemainingCount ?? 1),