Various improvements

This commit is contained in:
Ilya Laktyushin 2025-10-29 17:20:36 +04:00
parent 284d963b07
commit 5877f2c20d
103 changed files with 8267 additions and 1762 deletions

View file

@ -15163,3 +15163,8 @@ Error: %8$@";
"Privacy.SavedMusic.CustomHelp" = "You can restrict who can see your saved music with granular precision.";
"Privacy.SavedMusic.AlwaysShareWith.Title" = "Always Share With";
"Privacy.SavedMusic.NeverShareWith.Title" = "Never Share With";
"ScheduledMessages.Reminder.Delete" = "Delete Reminder";
"ScheduledMessages.Reminder.DeleteMany" = "Delete Reminders";
"Gift.Setup.NextDropIn" = "next drop in {m}:{s}";

View file

@ -1374,7 +1374,9 @@ public protocol SharedAccountContext: AnyObject {
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: ((StarGift.UniqueGift) -> Void)?) -> ViewController
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController
func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
func makeGiftAuctionInfoScreen(context: AccountContext, gift: StarGift, completion: (() -> Void)?) -> ViewController
func makeGiftAuctionScreen(context: AccountContext, gift: StarGift, auctionContext: GiftAuctionContext) -> ViewController
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
func makeContentReportScreen(context: AccountContext, subject: ReportContentSubject, forceDark: Bool, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void, requestSelectMessages: ((String, Data, String?) -> Void)?)
@ -1416,7 +1418,7 @@ public protocol SharedAccountContext: AnyObject {
func openCreateGroupCallUI(context: AccountContext, peerIds: [EnginePeer.Id], parentController: ViewController)
func makeNewContactScreen(context: AccountContext, firstName: String?, lastName: String?, phoneNumber: String?) -> ViewController
func makeNewContactScreen(context: AccountContext, peer: EnginePeer?, phoneNumber: String?, completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void) -> ViewController
func navigateToCurrentCall()
var hasOngoingCall: ValuePromise<Bool> { get }

View file

@ -73,7 +73,7 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
var presentationData: PresentationData {
didSet {
self.pillView.tintColor = self.presentationData.theme.rootController.navigationBar.primaryTextColor
self.pillView.tintColor = self.presentationData.theme.list.itemPrimaryTextColor.withMultipliedAlpha(self.presentationData.theme.overallDarkAppearance ? 0.2 : 0.07)
}
}
@ -107,9 +107,8 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
self.container.shouldAnimateDisappearance = true
self.pillView = UIImageView()
self.pillView.alpha = 0.2
self.pillView.image = generateFilledRoundedRectImage(size: CGSize(width: 36.0, height: 5.0), cornerRadius: 2.5, color: .black)?.withRenderingMode(.alwaysTemplate)
self.pillView.tintColor = self.presentationData.theme.rootController.navigationBar.primaryTextColor
self.pillView.image = generateStretchableFilledCircleImage(diameter: 5.0, color: .white)?.withRenderingMode(.alwaysTemplate)
self.pillView.tintColor = self.presentationData.theme.list.itemPrimaryTextColor.withMultipliedAlpha(self.presentationData.theme.overallDarkAppearance ? 0.2 : 0.07)
super.init()
@ -620,10 +619,9 @@ final class AttachmentContainer: ASDisplayNode, ASGestureRecognizerDelegate {
transition.updateTransformScale(node: self.container, scale: containerScale)
self.container.update(layout: containerLayout, canBeClosed: true, controllers: controllers, transition: transition)
if let image = self.pillView.image {
transition.updateFrame(view: self.pillView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((clipFrame.width - image.size.width) / 2.0), y: 5.0), size: image.size))
self.pillView.isHidden = layout.metrics.isTablet
}
let pillSize = CGSize(width: 36.0, height: 5.0)
transition.updateFrame(view: self.pillView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((clipFrame.width - pillSize.width) / 2.0), y: 5.0), size: pillSize))
self.pillView.isHidden = layout.metrics.isTablet
self.isUpdatingState = false
}

View file

@ -323,7 +323,7 @@ private final class AttachButtonComponent: CombinedComponent {
truncationType: .end,
maximumNumberOfLines: 1
),
availableSize: CGSize(width: 60.0, height: context.availableSize.height),
availableSize: CGSize(width: 64.0, height: context.availableSize.height),
transition: .immediate
)
@ -1892,7 +1892,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
let textPanelSideInset: CGFloat = 8.0
let defaultPanelSideInset: CGFloat = glassPanelSideInset
let panelSideInset: CGFloat = isSelecting ? textPanelSideInset : defaultPanelSideInset
let panelSideInset: CGFloat = (isSelecting ? textPanelSideInset : defaultPanelSideInset) + layout.safeInsets.left
var textPanelHeight: CGFloat = 0.0
var textPanelWidth: CGFloat = 0.0
if let textInputPanelNode = self.textInputPanelNode {

View file

@ -126,7 +126,8 @@ private final class CameraContext {
private let audioLevelPipe = ValuePipe<Float>()
fileprivate let modeChangePromise = ValuePromise<Camera.ModeChange>(.none)
var videoOutput: CameraVideoOutput?
var mainVideoOutput: CameraVideoOutput?
var additionalVideoOutput: CameraVideoOutput?
var simplePreviewView: CameraSimplePreviewView?
var secondaryPreviewView: CameraSimplePreviewView?
@ -345,11 +346,21 @@ private final class CameraContext {
if #available(iOS 13.0, *) {
front = connection.inputPorts.first?.sourceDevicePosition == .front
}
if sampleBuffer.type == kCMMediaType_Video {
Queue.mainQueue().async {
self.mainVideoOutput?.push(sampleBuffer, mirror: front)
}
}
self.savePreviewSnapshot(pixelBuffer: pixelBuffer, front: front)
self.lastSnapshotTimestamp = timestamp
self.savedSnapshot = true
}
}
self.mainDeviceContext?.output.processAudioBuffer = { [weak self] sampleBuffer in
let _ = self
}
self.additionalDeviceContext?.output.processSampleBuffer = { [weak self] sampleBuffer, pixelBuffer, connection in
guard let self, let additionalDeviceContext = self.additionalDeviceContext else {
return
@ -360,6 +371,11 @@ private final class CameraContext {
if #available(iOS 13.0, *) {
front = connection.inputPorts.first?.sourceDevicePosition == .front
}
Queue.mainQueue().async {
self.additionalVideoOutput?.push(sampleBuffer, mirror: front)
}
self.savePreviewSnapshot(pixelBuffer: pixelBuffer, front: front)
self.lastAdditionalSnapshotTimestamp = timestamp
self.savedAdditionalSnapshot = true
@ -387,10 +403,8 @@ private final class CameraContext {
front = connection.inputPorts.first?.sourceDevicePosition == .front
}
if sampleBuffer.type == kCMMediaType_Video {
Queue.mainQueue().async {
self.videoOutput?.push(sampleBuffer, mirror: front)
}
Queue.mainQueue().async {
self.mainVideoOutput?.push(sampleBuffer, mirror: front)
}
let timestamp = CACurrentMediaTime()
@ -400,48 +414,52 @@ private final class CameraContext {
self.savedSnapshot = true
}
}
if self.initialConfiguration.reportAudioLevel {
self.mainDeviceContext?.output.processAudioBuffer = { [weak self] sampleBuffer in
guard let self else {
return
}
var blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer)
let numSamplesInBuffer = CMSampleBufferGetNumSamples(sampleBuffer)
var audioBufferList = AudioBufferList()
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, blockBufferOut: &blockBuffer)
// for bufferCount in 0..<Int(audioBufferList.mNumberBuffers) {
let buffer = audioBufferList.mBuffers.mData
let size = audioBufferList.mBuffers.mDataByteSize
if let data = buffer?.bindMemory(to: Int16.self, capacity: Int(size)) {
processWaveformPreview(samples: data, count: numSamplesInBuffer)
}
// }
func processWaveformPreview(samples: UnsafePointer<Int16>, count: Int) {
for i in 0..<count {
var sample = samples[i]
if sample < 0 {
sample = -sample
}
if self.micLevelPeak < sample {
self.micLevelPeak = sample
}
self.micLevelPeakCount += 1
if self.micLevelPeakCount >= 1200 {
let level = Float(self.micLevelPeak) / 4000.0
self.audioLevelPipe.putNext(level)
self.micLevelPeak = 0
self.micLevelPeakCount = 0
}
}
}
}
self.mainDeviceContext?.output.processAudioBuffer = { [weak self] sampleBuffer in
let _ = self
}
// if self.initialConfiguration.reportAudioLevel {
// self.mainDeviceContext?.output.processAudioBuffer = { [weak self] sampleBuffer in
// guard let self else {
// return
// }
// var blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer)
// let numSamplesInBuffer = CMSampleBufferGetNumSamples(sampleBuffer)
// var audioBufferList = AudioBufferList()
//
// CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, blockBufferOut: &blockBuffer)
//
//// for bufferCount in 0..<Int(audioBufferList.mNumberBuffers) {
// let buffer = audioBufferList.mBuffers.mData
// let size = audioBufferList.mBuffers.mDataByteSize
// if let data = buffer?.bindMemory(to: Int16.self, capacity: Int(size)) {
// processWaveformPreview(samples: data, count: numSamplesInBuffer)
// }
//// }
//
// func processWaveformPreview(samples: UnsafePointer<Int16>, count: Int) {
// for i in 0..<count {
// var sample = samples[i]
// if sample < 0 {
// sample = -sample
// }
//
// if self.micLevelPeak < sample {
// self.micLevelPeak = sample
// }
// self.micLevelPeakCount += 1
//
// if self.micLevelPeakCount >= 1200 {
// let level = Float(self.micLevelPeak) / 4000.0
// self.audioLevelPipe.putNext(level)
//
// self.micLevelPeak = 0
// self.micLevelPeakCount = 0
// }
// }
// }
// }
// }
self.mainDeviceContext?.output.processCodes = { [weak self] codes in
self?.detectedCodesPipe.putNext(codes)
}
@ -1016,15 +1034,33 @@ public final class Camera {
}
}
public func setVideoOutput(_ output: CameraVideoOutput?) {
public func setMainVideoOutput(_ output: CameraVideoOutput?) {
let outputRef: Unmanaged<CameraVideoOutput>? = output.flatMap { Unmanaged.passRetained($0) }
self.queue.async {
if let context = self.contextRef?.takeUnretainedValue() {
if let outputRef {
context.videoOutput = outputRef.takeUnretainedValue()
context.mainVideoOutput = outputRef.takeUnretainedValue()
outputRef.release()
} else {
context.videoOutput = nil
context.mainVideoOutput = nil
}
} else {
Queue.mainQueue().async {
outputRef?.release()
}
}
}
}
public func setAdditionalVideoOutput(_ output: CameraVideoOutput?) {
let outputRef: Unmanaged<CameraVideoOutput>? = output.flatMap { Unmanaged.passRetained($0) }
self.queue.async {
if let context = self.contextRef?.takeUnretainedValue() {
if let outputRef {
context.additionalVideoOutput = outputRef.takeUnretainedValue()
outputRef.release()
} else {
context.additionalVideoOutput = nil
}
} else {
Queue.mainQueue().async {

View file

@ -642,8 +642,8 @@ extension CameraOutput: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureA
if let videoPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
self.processSampleBuffer?(sampleBuffer, videoPixelBuffer, connection)
} else {
// self.processAudioBuffer?(sampleBuffer)
} else if sampleBuffer.type == kCMMediaType_Audio {
self.processAudioBuffer?(sampleBuffer)
}
if let masterOutput = self.masterOutput {

View file

@ -280,7 +280,7 @@ final class ComposePollScreenComponent: Component {
let theme = environment.theme.withModalBlocksBackground()
let backgroundView = UIImageView(image: generateReorderingBackgroundImage(backgroundColor: theme.list.itemBlocksBackgroundColor))
backgroundView.frame = wrapperView.bounds.insetBy(dx: -10.0, dy: -10.0)
backgroundView.frame = wrapperView.bounds.insetBy(dx: -16.0, dy: -16.0)
snapshotView.frame = snapshotView.bounds
wrapperView.addSubview(backgroundView)

View file

@ -740,34 +740,31 @@ public class ContactsController: ViewController {
switch status {
case .allowed:
//let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
let controller = strongSelf.context.sharedContext.makeNewContactScreen(
context: strongSelf.context,
firstName: nil,
lastName: nil,
phoneNumber: nil
peer: nil,
phoneNumber: nil,
completion: { [weak self] peer, stableId, contactData in
guard let strongSelf = self else {
return
}
if let peer {
Queue.mainQueue().async {
if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(infoController)
}
}
}
} else if let stableId, let contactData {
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
}
}
}
)
navigationController.pushViewController(controller)
// navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
// guard let strongSelf = self else {
// return
// }
// if let peer = peer {
// DispatchQueue.main.async {
// if let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: nil, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
// if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
// navigationController.pushViewController(infoController)
// }
// }
// }
// } else {
// if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
// navigationController.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil))
// }
// }
// }), completed: nil, cancelled: nil))
}
case .notDetermined:
DeviceAccess.authorizeAccess(to: .contacts)

View file

@ -722,8 +722,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
theme: self.presentationData.theme,
strings: self.presentationData.strings,
metrics: layout.metrics,
placeholder: nil,
resetText: nil,
safeInsets: layout.safeInsets,
updated: { [weak self] query in
guard let self else {
return
@ -740,11 +739,11 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
)
),
environment: {},
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: layout.size.height)
containerSize: CGSize(width: layout.size.width, height: layout.size.height)
)
let bottomInset: CGFloat = layout.insets(options: .input).bottom
let searchInputFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
let searchInputFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
if let searchInputView = self.searchInput.view as? SearchInputPanelComponent.View {
if searchInputView.superview == nil {
self.view.addSubview(searchInputView)

View file

@ -340,11 +340,9 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
self.statusBar.statusBarStyle = theme.rootController.statusBarStyle.style
//TODO:localize
self.title = "Select Country"
if glass {
//TODO:localize
self.title = "Select Country"
} else {
let navigationContentNode = AuthorizationSequenceCountrySelectionNavigationContentNode(theme: theme, strings: strings, cancel: { [weak self] in
self?.dismissed?()

View file

@ -211,7 +211,6 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
private var searchInput: ComponentView<Empty>?
var isSearching = true
private var validLayout: ContainerViewLayout?
init(theme: PresentationTheme, strings: PresentationStrings, displayCodes: Bool, glass: Bool, itemSelected: @escaping (((String, String), String, Int)) -> Void) {
@ -300,12 +299,14 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
transition.updateFrame(view: self.tableView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
transition.updateFrame(view: self.searchTableView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height)))
let edgeEffectHeight: CGFloat = 88.0
let topEdgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: edgeEffectHeight))
transition.updateFrame(view: self.topEdgeEffectView, frame: topEdgeEffectFrame)
self.topEdgeEffectView.update(content: .clear, blur: true, alpha: 1.0, rect: topEdgeEffectFrame, edge: .top, edgeSize: topEdgeEffectFrame.height, transition: ComponentTransition(transition))
if self.glass {
let edgeEffectHeight: CGFloat = 88.0
let topEdgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: edgeEffectHeight))
transition.updateFrame(view: self.topEdgeEffectView, frame: topEdgeEffectFrame)
self.topEdgeEffectView.update(content: .clear, blur: true, alpha: 1.0, rect: topEdgeEffectFrame, edge: .top, edgeSize: topEdgeEffectFrame.height, transition: ComponentTransition(transition))
}
if self.isSearching {
if self.glass && self.isSearching {
let searchInput: ComponentView<Empty>
if let current = self.searchInput {
searchInput = current
@ -321,6 +322,7 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
theme: self.theme,
strings: self.strings,
metrics: layout.metrics,
safeInsets: layout.safeInsets,
updated: { [weak self] query in
guard let self else {
return
@ -337,10 +339,10 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
)
),
environment: {},
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: layout.size.height)
containerSize: CGSize(width: layout.size.width, height: layout.size.height)
)
let bottomInset: CGFloat = layout.insets(options: .input).bottom
let searchInputFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
let searchInputFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
if let searchInputView = searchInput.view as? SearchInputPanelComponent.View {
if searchInputView.superview == nil {
self.view.addSubview(searchInputView)

View file

@ -87,7 +87,7 @@ private final class WindowRootViewControllerView: UIView {
}
}
private final class WindowRootViewController: UIViewController {
private final class WindowRootViewController: UIViewController, UIWindowSceneDelegate {
private var voiceOverStatusObserver: AnyObject?
private var registeredForPreviewing = false
@ -183,7 +183,7 @@ private final class WindowRootViewController: UIViewController {
init() {
super.init(nibName: nil, bundle: nil)
self.extendedLayoutIncludesOpaqueBars = true
self.voiceOverStatusObserver = NotificationCenter.default.addObserver(forName: UIAccessibility.voiceOverStatusDidChangeNotification, object: nil, queue: OperationQueue.main, using: { _ in
@ -194,6 +194,10 @@ private final class WindowRootViewController: UIViewController {
} else {
self._systemUserInterfaceStyle.set(.light)
}
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
windowScene.delegate = self
}
}
required init?(coder aDecoder: NSCoder) {
@ -206,6 +210,11 @@ private final class WindowRootViewController: UIViewController {
}
}
@available(iOS 26.0, *)
func preferredWindowingControlStyle(for windowScene: UIWindowScene) -> UIWindowScene.WindowingControlStyle {
return .minimal
}
override var preferredScreenEdgesDeferringSystemGestures: UIRectEdge {
return self.gestureEdges
}

View file

@ -250,7 +250,7 @@ public final class NavigationContainer: ASDisplayNode, ASGestureRecognizerDelega
bottomController.viewWillAppear(true)
let bottomNode = bottomController.displayNode
let screenCornerRadius = self.minimizedContainer == nil ? layout.deviceMetrics.screenCornerRadius : 0.0
let screenCornerRadius = self.minimizedContainer == nil && self.state.canBeClosed != true ? layout.deviceMetrics.screenCornerRadius : 0.0
let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, isInteractive: true, isFlat: self.isFlat, container: self, topNode: topNode, topNavigationBar: topController.transitionNavigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.transitionNavigationBar, screenCornerRadius: screenCornerRadius, didUpdateProgress: { [weak self, weak bottomController] progress, transition, topFrame, bottomFrame in
if let strongSelf = self {
if let top = strongSelf.state.top {
@ -491,7 +491,7 @@ public final class NavigationContainer: ASDisplayNode, ASGestureRecognizerDelega
}
toValue.value.setIgnoreAppearanceMethodInvocations(false)
let screenCornerRadius = self.minimizedContainer == nil ? layout.deviceMetrics.screenCornerRadius : 0.0
let screenCornerRadius = self.minimizedContainer == nil && self.state.canBeClosed != true ? layout.deviceMetrics.screenCornerRadius : 0.0
let topTransition = TopTransition(type: transitionType, previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, isInteractive: false, isFlat: self.isFlat, container: self, topNode: topController.displayNode, topNavigationBar: topController.transitionNavigationBar, bottomNode: bottomController.displayNode, bottomNavigationBar: bottomController.transitionNavigationBar, screenCornerRadius: screenCornerRadius, didUpdateProgress: { [weak self] _, transition, topFrame, bottomFrame in
guard let strongSelf = self else {
return

View file

@ -241,8 +241,10 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
open func navigationLayout(layout: ContainerViewLayout) -> NavigationLayout {
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
var defaultNavigationBarHeight: CGFloat
if self._presentedInModal && layout.orientation == .portrait {
defaultNavigationBarHeight = self._hasGlassStyle ? 66.0 : 56.0
if self._presentedInModal && self._hasGlassStyle {
defaultNavigationBarHeight = 66.0
} else if self._presentedInModal && layout.orientation == .portrait {
defaultNavigationBarHeight = 56.0
} else {
defaultNavigationBarHeight = 44.0
}

View file

@ -45,11 +45,17 @@ static const void *positionChangedKey = &positionChangedKey;
if (self != nil) {
_offIconView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PermissionSwitchOff.png")];
_onIconView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PermissionSwitchOn.png")];
self.layer.cornerRadius = 17.0f;
if (iosMajorVersion() >= 26) {
self.layer.cornerRadius = 14.0f;
} else {
self.layer.cornerRadius = 17.0f;
}
self.backgroundColor = [UIColor redColor];
self.tintColor = [UIColor redColor];
UIView *handleView = self.subviews[0].subviews.lastObject;
if (iosMajorVersion() >= 13) {
if (iosMajorVersion() >= 26) {
handleView = self.subviews[0].subviews.lastObject;
} else if (iosMajorVersion() >= 13) {
handleView = self.subviews[0].subviews[1].subviews.lastObject;
} else {
handleView = self.subviews[0].subviews.lastObject;
@ -91,7 +97,9 @@ static const void *positionChangedKey = &positionChangedKey;
- (void)updateIconFrame {
CGPoint offset = CGPointZero;
if (iosMajorVersion() >= 12) {
if (iosMajorVersion() >= 26) {
offset = CGPointMake(-10.0, -9.0 - TGScreenPixel);
} else if (iosMajorVersion() >= 12) {
offset = CGPointMake(-7.0, -3.0);
}

View file

@ -1225,7 +1225,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.presentationData.theme.theme, top: hasTopCorners, bottom: hasBottomCorners, glass: item.systemStyle == .glass) : nil
if let backgroundNode = strongSelf.backgroundNode {
strongSelf.maskNode.frame = backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.maskNode.frame = backgroundNode.frame.insetBy(dx: params.leftInset, dy: -UIScreenPixel)
}
}

View file

@ -1453,8 +1453,8 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
theme: self.presentationData.theme,
strings: self.presentationData.strings,
metrics: layout.metrics,
safeInsets: layout.safeInsets,
placeholder: self.presentationData.strings.Map_Search,
resetText: nil,
updated: { [weak self] query in
guard let self, let controller = self.controller else {
return
@ -1470,11 +1470,11 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
)
),
environment: {},
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: layout.size.height)
containerSize: CGSize(width: layout.size.width, height: layout.size.height)
)
let bottomInset: CGFloat = layout.insets(options: .input).bottom
let searchInputFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
let searchInputFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
if let searchInputView = searchInput.view as? SearchInputPanelComponent.View {
if searchInputView.superview == nil {
self.view.addSubview(searchInputView)

View file

@ -1616,9 +1616,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
let firstTime = self.validLayout == nil
self.validLayout = (layout, navigationBarHeight)
if firstTime {
self.updateSelectionState(animated: false, updateLayout: false)
}
self.updateSelectionState(animated: false, updateLayout: false)
var insets = layout.insets(options: [])
insets.top += navigationBarHeight
@ -2592,7 +2590,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
environment: {},
containerSize: barButtonSize
)
let cancelButtonFrame = CGRect(origin: CGPoint(x: barButtonSideInset, y: barButtonSideInset), size: cancelButtonSize)
let cancelButtonFrame = CGRect(origin: CGPoint(x: barButtonSideInset + layout.safeInsets.left, y: barButtonSideInset), size: cancelButtonSize)
if let view = cancelButton.view {
if view.superview == nil {
self.view.addSubview(view)
@ -2627,7 +2625,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
environment: {},
containerSize: barButtonSize
)
let moreButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - moreButtonSize.width - barButtonSideInset, y: barButtonSideInset), size: moreButtonSize)
let moreButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - moreButtonSize.width - barButtonSideInset - layout.safeInsets.right, y: barButtonSideInset), size: moreButtonSize)
if let view = moreButton.view {
if view.superview == nil {
self.view.addSubview(view)

View file

@ -292,7 +292,7 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
transition: context.transition
)
let bottomText = Condition(mode == .create) {
let bottomText = Condition(context.component.mode.isCreate) {
bottomText.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(string: environment.strings.CreateExternalStream_StartStreamingInfo, font: Font.regular(13.0), textColor: theme.list.itemSecondaryTextColor, paragraphAlignment: .center)),
@ -305,15 +305,15 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
)
}
let buttonAttributedString = NSMutableAttributedString(string: mode == .create ? environment.strings.CreateExternalStream_StartStreaming : environment.strings.Common_Close, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
let buttonAttributedString = NSMutableAttributedString(string: mode.isCreate ? environment.strings.CreateExternalStream_StartStreaming : environment.strings.Common_Close, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
let button = button.update(
component: ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: mode == .create ? UIColor(rgb: 0xfa325a) : theme.list.itemCheckColors.fillColor,
foreground: mode == .create ? .white : theme.list.itemCheckColors.foregroundColor,
pressedColor: mode == .create ? UIColor(rgb: 0xfa325a) : theme.list.itemCheckColors.fillColor,
isShimmering: mode == .create
color: mode.isCreate ? UIColor(rgb: 0xfa325a) : theme.list.itemCheckColors.fillColor,
foreground: mode.isCreate ? .white : theme.list.itemCheckColors.foregroundColor,
pressedColor: mode.isCreate ? UIColor(rgb: 0xfa325a) : theme.list.itemCheckColors.fillColor,
isShimmering: mode.isCreate
),
content: AnyComponentWithIdentity(
id: AnyHashable(0),
@ -322,15 +322,20 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
isEnabled: true,
displaysProgress: false,
action: { [weak state] in
guard let state = state, let controller = controller() else {
guard let state = state, let controller = controller() as? CreateExternalMediaStreamScreen else {
return
}
switch mode {
case .create:
state.createAndJoinGroupCall(baseController: controller, completion: { [weak controller] in
controller?.dismiss()
})
case let .create(livestream):
if livestream {
controller.completion?()
} else {
state.createAndJoinGroupCall(baseController: controller, completion: { [weak controller] in
controller?.completion?()
controller?.dismiss()
})
}
case .view:
controller.dismiss()
}
@ -480,7 +485,7 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
let buttonFrame = CGRect(origin: CGPoint(x: buttonSideInset, y: context.availableSize.height - bottomInset - button.size.height), size: button.size)
if let bottomText = bottomText {
if let bottomText {
context.add(bottomText
.position(CGPoint(x: context.availableSize.width / 2.0, y: buttonFrame.minY - 12.0 - bottomText.size.height / 2.0))
)
@ -496,19 +501,35 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
}
public final class CreateExternalMediaStreamScreen: ViewControllerComponentContainer {
public enum Mode {
case create
public enum Mode: Equatable {
case create(liveStream: Bool)
case view
var isCreate: Bool {
if case .create = self {
return true
} else {
return false
}
}
}
private let context: AccountContext
private let peerId: EnginePeer.Id
private let mode: Mode
fileprivate let completion: (() -> Void)?
public init(context: AccountContext, peerId: EnginePeer.Id, credentialsPromise: Promise<GroupCallStreamCredentials>?, mode: Mode) {
public init(
context: AccountContext,
peerId: EnginePeer.Id,
credentialsPromise: Promise<GroupCallStreamCredentials>?,
mode: Mode,
completion: (() -> Void)? = nil
) {
self.context = context
self.peerId = peerId
self.mode = mode
self.completion = completion
super.init(context: context, component: CreateExternalMediaStreamScreenComponent(context: context, peerId: peerId, mode: mode, credentialsPromise: credentialsPromise), navigationBarAppearance: .none, theme: .dark)

View file

@ -50,7 +50,7 @@ private func getUserPeer(engine: TelegramEngine, peerId: EnginePeer.Id) -> Signa
public func openAddPersonContactImpl(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void, completion: @escaping () -> Void = {}) {
let _ = (getUserPeer(engine: context.engine, peerId: peerId)
|> deliverOnMainQueue).start(next: { peer, statusSettings in
guard let peer, case let .user(user) = peer, let contactData = DeviceContactExtendedData(peer: peer) else {
guard let peer, case let .user(user) = peer else {
return
}
@ -59,13 +59,30 @@ public func openAddPersonContactImpl(context: AccountContext, updatedPresentatio
shareViaException = statusSettings.contains(.addExceptionWhenAddingContact)
}
pushController(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), updatedPresentationData: updatedPresentationData, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
if let peer = peer as? TelegramUser {
completion()
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), nil)
let _ = shareViaException
let controller = context.sharedContext.makeNewContactScreen(
context: context,
peer: peer,
phoneNumber: user.phone,
completion: { peer, _, _ in
if let peer {
completion()
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).string, true)), nil)
}
}
}), completed: nil, cancelled: nil))
)
pushController(controller)
// pushController(deviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), updatedPresentationData: updatedPresentationData, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
// if let peer = peer as? TelegramUser {
// completion()
//
// let presentationData = context.sharedContext.currentPresentationData.with { $0 }
// present(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), nil)
// }
// }), completed: nil, cancelled: nil))
})
}

View file

@ -66,6 +66,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[84480319] = { return Api.AttachMenuPeerType.parse_attachMenuPeerTypeChat($0) }
dict[-247016673] = { return Api.AttachMenuPeerType.parse_attachMenuPeerTypePM($0) }
dict[2104224014] = { return Api.AttachMenuPeerType.parse_attachMenuPeerTypeSameBotPM($0) }
dict[822231244] = { return Api.AuctionBidLevel.parse_auctionBidLevel($0) }
dict[-1392388579] = { return Api.Authorization.parse_authorization($0) }
dict[-1163561432] = { return Api.AutoDownloadSettings.parse_autoDownloadSettings($0) }
dict[-2124403385] = { return Api.AutoSaveException.parse_autoSaveException($0) }
@ -301,7 +302,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[286776671] = { return Api.GeoPoint.parse_geoPointEmpty($0) }
dict[-565420653] = { return Api.GeoPointAddress.parse_geoPointAddress($0) }
dict[-29248689] = { return Api.GlobalPrivacySettings.parse_globalPrivacySettings($0) }
dict[-674602536] = { return Api.GroupCall.parse_groupCall($0) }
dict[-273500649] = { return Api.GroupCall.parse_groupCall($0) }
dict[2004925620] = { return Api.GroupCall.parse_groupCallDiscarded($0) }
dict[-297595771] = { return Api.GroupCallDonor.parse_groupCallDonor($0) }
dict[445316222] = { return Api.GroupCallMessage.parse_groupCallMessage($0) }
@ -396,6 +397,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-625298705] = { return Api.InputInvoice.parse_inputInvoicePremiumGiftStars($0) }
dict[-1020867857] = { return Api.InputInvoice.parse_inputInvoiceSlug($0) }
dict[-396206446] = { return Api.InputInvoice.parse_inputInvoiceStarGift($0) }
dict[2010287526] = { return Api.InputInvoice.parse_inputInvoiceStarGiftAuctionBid($0) }
dict[153344209] = { return Api.InputInvoice.parse_inputInvoiceStarGiftDropOriginalDetails($0) }
dict[-1710536520] = { return Api.InputInvoice.parse_inputInvoiceStarGiftPrepaidUpgrade($0) }
dict[-1012968668] = { return Api.InputInvoice.parse_inputInvoiceStarGiftResale($0) }
@ -588,7 +590,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) }
dict[-1730095465] = { return Api.MessageAction.parse_messageActionGeoProximityReached($0) }
dict[1456486804] = { return Api.MessageAction.parse_messageActionGiftCode($0) }
dict[1818391802] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
dict[1223234306] = { return Api.MessageAction.parse_messageActionGiftPremium($0) }
dict[1171632161] = { return Api.MessageAction.parse_messageActionGiftStars($0) }
dict[-1465661799] = { return Api.MessageAction.parse_messageActionGiftTon($0) }
dict[-1475391004] = { return Api.MessageAction.parse_messageActionGiveawayLaunch($0) }
@ -980,6 +982,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[520210263] = { return Api.StarGiftAttributeId.parse_starGiftAttributeIdBackdrop($0) }
dict[1219145276] = { return Api.StarGiftAttributeId.parse_starGiftAttributeIdModel($0) }
dict[1242965043] = { return Api.StarGiftAttributeId.parse_starGiftAttributeIdPattern($0) }
dict[-483580782] = { return Api.StarGiftAuctionState.parse_starGiftAuctionState($0) }
dict[676935593] = { return Api.StarGiftAuctionState.parse_starGiftAuctionStateFinished($0) }
dict[-30197422] = { return Api.StarGiftAuctionState.parse_starGiftAuctionStateNotModified($0) }
dict[-165829476] = { return Api.StarGiftAuctionUserState.parse_starGiftAuctionUserState($0) }
dict[-1653926992] = { return Api.StarGiftCollection.parse_starGiftCollection($0) }
dict[-1712704739] = { return Api.StarGiftUpgradePrice.parse_starGiftUpgradePrice($0) }
dict[-586389774] = { return Api.StarRefProgram.parse_starRefProgram($0) }
@ -1182,6 +1188,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[2103604867] = { return Api.Update.parse_updateSentStoryReaction($0) }
dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) }
dict[-245208620] = { return Api.Update.parse_updateSmsJob($0) }
dict[1222788802] = { return Api.Update.parse_updateStarGiftAuctionState($0) }
dict[-598150370] = { return Api.Update.parse_updateStarGiftAuctionUserState($0) }
dict[1317053305] = { return Api.Update.parse_updateStarsBalance($0) }
dict[-1518030823] = { return Api.Update.parse_updateStarsRevenueStatus($0) }
dict[834816008] = { return Api.Update.parse_updateStickerSets($0) }
@ -1471,6 +1479,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1803939105] = { return Api.payments.ResaleStarGifts.parse_resaleStarGifts($0) }
dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) }
dict[-1779201615] = { return Api.payments.SavedStarGifts.parse_savedStarGifts($0) }
dict[-2061303084] = { return Api.payments.StarGiftAuctionState.parse_starGiftAuctionState($0) }
dict[-1977011469] = { return Api.payments.StarGiftCollections.parse_starGiftCollections($0) }
dict[-1598402793] = { return Api.payments.StarGiftCollections.parse_starGiftCollectionsNotModified($0) }
dict[1038213101] = { return Api.payments.StarGiftUpgradePreview.parse_starGiftUpgradePreview($0) }
@ -1619,6 +1628,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.AttachMenuPeerType:
_1.serialize(buffer, boxed)
case let _1 as Api.AuctionBidLevel:
_1.serialize(buffer, boxed)
case let _1 as Api.Authorization:
_1.serialize(buffer, boxed)
case let _1 as Api.AutoDownloadSettings:
@ -2203,6 +2214,10 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.StarGiftAttributeId:
_1.serialize(buffer, boxed)
case let _1 as Api.StarGiftAuctionState:
_1.serialize(buffer, boxed)
case let _1 as Api.StarGiftAuctionUserState:
_1.serialize(buffer, boxed)
case let _1 as Api.StarGiftCollection:
_1.serialize(buffer, boxed)
case let _1 as Api.StarGiftUpgradePrice:
@ -2619,6 +2634,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.payments.SavedStarGifts:
_1.serialize(buffer, boxed)
case let _1 as Api.payments.StarGiftAuctionState:
_1.serialize(buffer, boxed)
case let _1 as Api.payments.StarGiftCollections:
_1.serialize(buffer, boxed)
case let _1 as Api.payments.StarGiftUpgradePreview:

View file

@ -386,6 +386,50 @@ public extension Api {
}
}
public extension Api {
enum AuctionBidLevel: TypeConstructorDescription {
case auctionBidLevel(pos: Int32, amount: Int64, date: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .auctionBidLevel(let pos, let amount, let date):
if boxed {
buffer.appendInt32(822231244)
}
serializeInt32(pos, buffer: buffer, boxed: false)
serializeInt64(amount, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .auctionBidLevel(let pos, let amount, let date):
return ("auctionBidLevel", [("pos", pos as Any), ("amount", amount as Any), ("date", date as Any)])
}
}
public static func parse_auctionBidLevel(_ reader: BufferReader) -> AuctionBidLevel? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.AuctionBidLevel.auctionBidLevel(pos: _1!, amount: _2!, date: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum Authorization: TypeConstructorDescription {
case authorization(flags: Int32, hash: Int64, deviceModel: String, platform: String, systemVersion: String, apiId: Int32, appName: String, appVersion: String, dateCreated: Int32, dateActive: Int32, ip: String, country: String, region: String)
@ -1168,61 +1212,3 @@ public extension Api {
}
}
public extension Api {
enum BotBusinessConnection: TypeConstructorDescription {
case botBusinessConnection(flags: Int32, connectionId: String, userId: Int64, dcId: Int32, date: Int32, rights: Api.BusinessBotRights?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botBusinessConnection(let flags, let connectionId, let userId, let dcId, let date, let rights):
if boxed {
buffer.appendInt32(-1892371723)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(connectionId, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(dcId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {rights!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botBusinessConnection(let flags, let connectionId, let userId, let dcId, let date, let rights):
return ("botBusinessConnection", [("flags", flags as Any), ("connectionId", connectionId as Any), ("userId", userId as Any), ("dcId", dcId as Any), ("date", date as Any), ("rights", rights as Any)])
}
}
public static func parse_botBusinessConnection(_ reader: BufferReader) -> BotBusinessConnection? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Api.BusinessBotRights?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.BusinessBotRights
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.BotBusinessConnection.botBusinessConnection(flags: _1!, connectionId: _2!, userId: _3!, dcId: _4!, date: _5!, rights: _6)
}
else {
return nil
}
}
}
}

View file

@ -566,6 +566,7 @@ public extension Api {
case inputInvoicePremiumGiftStars(flags: Int32, userId: Api.InputUser, months: Int32, message: Api.TextWithEntities?)
case inputInvoiceSlug(slug: String)
case inputInvoiceStarGift(flags: Int32, peer: Api.InputPeer, giftId: Int64, message: Api.TextWithEntities?)
case inputInvoiceStarGiftAuctionBid(flags: Int32, peer: Api.InputPeer, giftId: Int64, bidAmount: Int64, message: Api.TextWithEntities?)
case inputInvoiceStarGiftDropOriginalDetails(stargift: Api.InputSavedStarGift)
case inputInvoiceStarGiftPrepaidUpgrade(peer: Api.InputPeer, hash: String)
case inputInvoiceStarGiftResale(flags: Int32, slug: String, toId: Api.InputPeer)
@ -632,6 +633,16 @@ public extension Api {
serializeInt64(giftId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
break
case .inputInvoiceStarGiftAuctionBid(let flags, let peer, let giftId, let bidAmount, let message):
if boxed {
buffer.appendInt32(2010287526)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt64(giftId, buffer: buffer, boxed: false)
serializeInt64(bidAmount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
break
case .inputInvoiceStarGiftDropOriginalDetails(let stargift):
if boxed {
buffer.appendInt32(153344209)
@ -694,6 +705,8 @@ public extension Api {
return ("inputInvoiceSlug", [("slug", slug as Any)])
case .inputInvoiceStarGift(let flags, let peer, let giftId, let message):
return ("inputInvoiceStarGift", [("flags", flags as Any), ("peer", peer as Any), ("giftId", giftId as Any), ("message", message as Any)])
case .inputInvoiceStarGiftAuctionBid(let flags, let peer, let giftId, let bidAmount, let message):
return ("inputInvoiceStarGiftAuctionBid", [("flags", flags as Any), ("peer", peer as Any), ("giftId", giftId as Any), ("bidAmount", bidAmount as Any), ("message", message as Any)])
case .inputInvoiceStarGiftDropOriginalDetails(let stargift):
return ("inputInvoiceStarGiftDropOriginalDetails", [("stargift", stargift as Any)])
case .inputInvoiceStarGiftPrepaidUpgrade(let peer, let hash):
@ -842,6 +855,33 @@ public extension Api {
return nil
}
}
public static func parse_inputInvoiceStarGiftAuctionBid(_ reader: BufferReader) -> InputInvoice? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputPeer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
var _3: Int64?
_3 = reader.readInt64()
var _4: Int64?
_4 = reader.readInt64()
var _5: Api.TextWithEntities?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputInvoice.inputInvoiceStarGiftAuctionBid(flags: _1!, peer: _2!, giftId: _3!, bidAmount: _4!, message: _5)
}
else {
return nil
}
}
public static func parse_inputInvoiceStarGiftDropOriginalDetails(_ reader: BufferReader) -> InputInvoice? {
var _1: Api.InputSavedStarGift?
if let signature = reader.readInt32() {

View file

@ -1044,7 +1044,7 @@ public extension Api {
case messageActionGameScore(gameId: Int64, score: Int32)
case messageActionGeoProximityReached(fromId: Api.Peer, toId: Api.Peer, distance: Int32)
case messageActionGiftCode(flags: Int32, boostPeer: Api.Peer?, months: Int32, slug: String, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
case messageActionGiftPremium(flags: Int32, currency: String, amount: Int64, days: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, message: Api.TextWithEntities?)
case messageActionGiftStars(flags: Int32, currency: String, amount: Int64, stars: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?)
case messageActionGiftTon(flags: Int32, currency: String, amount: Int64, cryptoCurrency: String, cryptoAmount: Int64, transactionId: String?)
case messageActionGiveawayLaunch(flags: Int32, stars: Int64?)
@ -1235,14 +1235,14 @@ public extension Api {
if Int(flags) & Int(1 << 3) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {message!.serialize(buffer, true)}
break
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
case .messageActionGiftPremium(let flags, let currency, let amount, let days, let cryptoCurrency, let cryptoAmount, let message):
if boxed {
buffer.appendInt32(1818391802)
buffer.appendInt32(1223234306)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(currency, buffer: buffer, boxed: false)
serializeInt64(amount, buffer: buffer, boxed: false)
serializeInt32(months, buffer: buffer, boxed: false)
serializeInt32(days, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(cryptoCurrency!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(cryptoAmount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
@ -1627,8 +1627,8 @@ public extension Api {
return ("messageActionGeoProximityReached", [("fromId", fromId as Any), ("toId", toId as Any), ("distance", distance as Any)])
case .messageActionGiftCode(let flags, let boostPeer, let months, let slug, let currency, let amount, let cryptoCurrency, let cryptoAmount, let message):
return ("messageActionGiftCode", [("flags", flags as Any), ("boostPeer", boostPeer as Any), ("months", months as Any), ("slug", slug as Any), ("currency", currency as Any), ("amount", amount as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
case .messageActionGiftPremium(let flags, let currency, let amount, let months, let cryptoCurrency, let cryptoAmount, let message):
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("months", months as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
case .messageActionGiftPremium(let flags, let currency, let amount, let days, let cryptoCurrency, let cryptoAmount, let message):
return ("messageActionGiftPremium", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("days", days as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("message", message as Any)])
case .messageActionGiftStars(let flags, let currency, let amount, let stars, let cryptoCurrency, let cryptoAmount, let transactionId):
return ("messageActionGiftStars", [("flags", flags as Any), ("currency", currency as Any), ("amount", amount as Any), ("stars", stars as Any), ("cryptoCurrency", cryptoCurrency as Any), ("cryptoAmount", cryptoAmount as Any), ("transactionId", transactionId as Any)])
case .messageActionGiftTon(let flags, let currency, let amount, let cryptoCurrency, let cryptoAmount, let transactionId):
@ -1991,7 +1991,7 @@ public extension Api {
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, months: _4!, cryptoCurrency: _5, cryptoAmount: _6, message: _7)
return Api.MessageAction.messageActionGiftPremium(flags: _1!, currency: _2!, amount: _3!, days: _4!, cryptoCurrency: _5, cryptoAmount: _6, message: _7)
}
else {
return nil

View file

@ -1,3 +1,61 @@
public extension Api {
enum BotBusinessConnection: TypeConstructorDescription {
case botBusinessConnection(flags: Int32, connectionId: String, userId: Int64, dcId: Int32, date: Int32, rights: Api.BusinessBotRights?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botBusinessConnection(let flags, let connectionId, let userId, let dcId, let date, let rights):
if boxed {
buffer.appendInt32(-1892371723)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(connectionId, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(dcId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {rights!.serialize(buffer, true)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botBusinessConnection(let flags, let connectionId, let userId, let dcId, let date, let rights):
return ("botBusinessConnection", [("flags", flags as Any), ("connectionId", connectionId as Any), ("userId", userId as Any), ("dcId", dcId as Any), ("date", date as Any), ("rights", rights as Any)])
}
}
public static func parse_botBusinessConnection(_ reader: BufferReader) -> BotBusinessConnection? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Int64?
_3 = reader.readInt64()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
_5 = reader.readInt32()
var _6: Api.BusinessBotRights?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_6 = Api.parse(reader, signature: signature) as? Api.BusinessBotRights
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.BotBusinessConnection.botBusinessConnection(flags: _1!, connectionId: _2!, userId: _3!, dcId: _4!, date: _5!, rights: _6)
}
else {
return nil
}
}
}
}
public extension Api {
enum BotCommand: TypeConstructorDescription {
case botCommand(command: String, description: String)
@ -1184,49 +1242,3 @@ public extension Api {
}
}
public extension Api {
enum BusinessGreetingMessage: TypeConstructorDescription {
case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
if boxed {
buffer.appendInt32(-451302485)
}
serializeInt32(shortcutId, buffer: buffer, boxed: false)
recipients.serialize(buffer, true)
serializeInt32(noActivityDays, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)])
}
}
public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.BusinessRecipients?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!)
}
else {
return nil
}
}
}
}

View file

@ -788,6 +788,158 @@ public extension Api {
}
}
public extension Api {
enum StarGiftAuctionState: TypeConstructorDescription {
case starGiftAuctionState(version: Int32, minBidAmount: Int64, bidLevels: [Api.AuctionBidLevel], topBidders: [Int64], dropSize: Int32, nextDropAt: Int32, dropsLeft: Int32, dropsTotal: Int32)
case starGiftAuctionStateFinished
case starGiftAuctionStateNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starGiftAuctionState(let version, let minBidAmount, let bidLevels, let topBidders, let dropSize, let nextDropAt, let dropsLeft, let dropsTotal):
if boxed {
buffer.appendInt32(-483580782)
}
serializeInt32(version, buffer: buffer, boxed: false)
serializeInt64(minBidAmount, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(bidLevels.count))
for item in bidLevels {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(topBidders.count))
for item in topBidders {
serializeInt64(item, buffer: buffer, boxed: false)
}
serializeInt32(dropSize, buffer: buffer, boxed: false)
serializeInt32(nextDropAt, buffer: buffer, boxed: false)
serializeInt32(dropsLeft, buffer: buffer, boxed: false)
serializeInt32(dropsTotal, buffer: buffer, boxed: false)
break
case .starGiftAuctionStateFinished:
if boxed {
buffer.appendInt32(676935593)
}
break
case .starGiftAuctionStateNotModified:
if boxed {
buffer.appendInt32(-30197422)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starGiftAuctionState(let version, let minBidAmount, let bidLevels, let topBidders, let dropSize, let nextDropAt, let dropsLeft, let dropsTotal):
return ("starGiftAuctionState", [("version", version as Any), ("minBidAmount", minBidAmount as Any), ("bidLevels", bidLevels as Any), ("topBidders", topBidders as Any), ("dropSize", dropSize as Any), ("nextDropAt", nextDropAt as Any), ("dropsLeft", dropsLeft as Any), ("dropsTotal", dropsTotal as Any)])
case .starGiftAuctionStateFinished:
return ("starGiftAuctionStateFinished", [])
case .starGiftAuctionStateNotModified:
return ("starGiftAuctionStateNotModified", [])
}
}
public static func parse_starGiftAuctionState(_ reader: BufferReader) -> StarGiftAuctionState? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: [Api.AuctionBidLevel]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AuctionBidLevel.self)
}
var _4: [Int64]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
}
var _5: Int32?
_5 = reader.readInt32()
var _6: Int32?
_6 = reader.readInt32()
var _7: Int32?
_7 = reader.readInt32()
var _8: Int32?
_8 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.StarGiftAuctionState.starGiftAuctionState(version: _1!, minBidAmount: _2!, bidLevels: _3!, topBidders: _4!, dropSize: _5!, nextDropAt: _6!, dropsLeft: _7!, dropsTotal: _8!)
}
else {
return nil
}
}
public static func parse_starGiftAuctionStateFinished(_ reader: BufferReader) -> StarGiftAuctionState? {
return Api.StarGiftAuctionState.starGiftAuctionStateFinished
}
public static func parse_starGiftAuctionStateNotModified(_ reader: BufferReader) -> StarGiftAuctionState? {
return Api.StarGiftAuctionState.starGiftAuctionStateNotModified
}
}
}
public extension Api {
enum StarGiftAuctionUserState: TypeConstructorDescription {
case starGiftAuctionUserState(flags: Int32, bidAmount: Int64?, bidDate: Int32?, minBidAmount: Int64?, acquiredCount: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starGiftAuctionUserState(let flags, let bidAmount, let bidDate, let minBidAmount, let acquiredCount):
if boxed {
buffer.appendInt32(-165829476)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(bidAmount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(bidDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(minBidAmount!, buffer: buffer, boxed: false)}
serializeInt32(acquiredCount, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starGiftAuctionUserState(let flags, let bidAmount, let bidDate, let minBidAmount, let acquiredCount):
return ("starGiftAuctionUserState", [("flags", flags as Any), ("bidAmount", bidAmount as Any), ("bidDate", bidDate as Any), ("minBidAmount", minBidAmount as Any), ("acquiredCount", acquiredCount as Any)])
}
}
public static func parse_starGiftAuctionUserState(_ reader: BufferReader) -> StarGiftAuctionUserState? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt64() }
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
var _4: Int64?
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt64() }
var _5: Int32?
_5 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
let _c5 = _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.StarGiftAuctionUserState.starGiftAuctionUserState(flags: _1!, bidAmount: _2, bidDate: _3, minBidAmount: _4, acquiredCount: _5!)
}
else {
return nil
}
}
}
}
public extension Api {
enum StarGiftCollection: TypeConstructorDescription {
case starGiftCollection(flags: Int32, collectionId: Int32, title: String, icon: Api.Document?, giftsCount: Int32, hash: Int64)
@ -1442,271 +1594,3 @@ public extension Api {
}
}
public extension Api {
enum StarsTransaction: TypeConstructorDescription {
case starsTransaction(flags: Int32, id: String, amount: Api.StarsAmount, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?, subscriptionPeriod: Int32?, giveawayPostId: Int32?, stargift: Api.StarGift?, floodskipNumber: Int32?, starrefCommissionPermille: Int32?, starrefPeer: Api.Peer?, starrefAmount: Api.StarsAmount?, paidMessages: Int32?, premiumGiftMonths: Int32?, adsProceedsFromDate: Int32?, adsProceedsToDate: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate):
if boxed {
buffer.appendInt32(325426864)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(id, buffer: buffer, boxed: false)
amount.serialize(buffer, true)
serializeInt32(date, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
if Int(flags) & Int(1 << 5) != 0 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 5) != 0 {serializeString(transactionUrl!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 7) != 0 {serializeBytes(botPayload!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {serializeInt32(msgId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 9) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(extendedMedia!.count))
for item in extendedMedia! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 12) != 0 {serializeInt32(subscriptionPeriod!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 13) != 0 {serializeInt32(giveawayPostId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 14) != 0 {stargift!.serialize(buffer, true)}
if Int(flags) & Int(1 << 15) != 0 {serializeInt32(floodskipNumber!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 16) != 0 {serializeInt32(starrefCommissionPermille!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {starrefPeer!.serialize(buffer, true)}
if Int(flags) & Int(1 << 17) != 0 {starrefAmount!.serialize(buffer, true)}
if Int(flags) & Int(1 << 19) != 0 {serializeInt32(paidMessages!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 20) != 0 {serializeInt32(premiumGiftMonths!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsFromDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsToDate!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate):
return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("amount", amount as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any), ("subscriptionPeriod", subscriptionPeriod as Any), ("giveawayPostId", giveawayPostId as Any), ("stargift", stargift as Any), ("floodskipNumber", floodskipNumber as Any), ("starrefCommissionPermille", starrefCommissionPermille as Any), ("starrefPeer", starrefPeer as Any), ("starrefAmount", starrefAmount as Any), ("paidMessages", paidMessages as Any), ("premiumGiftMonths", premiumGiftMonths as Any), ("adsProceedsFromDate", adsProceedsFromDate as Any), ("adsProceedsToDate", adsProceedsToDate as Any)])
}
}
public static func parse_starsTransaction(_ reader: BufferReader) -> StarsTransaction? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Api.StarsAmount?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.StarsAmount
}
var _4: Int32?
_4 = reader.readInt32()
var _5: Api.StarsTransactionPeer?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.StarsTransactionPeer
}
var _6: String?
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
var _7: String?
if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) }
var _8: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _9: Int32?
if Int(_1!) & Int(1 << 5) != 0 {_9 = reader.readInt32() }
var _10: String?
if Int(_1!) & Int(1 << 5) != 0 {_10 = parseString(reader) }
var _11: Buffer?
if Int(_1!) & Int(1 << 7) != 0 {_11 = parseBytes(reader) }
var _12: Int32?
if Int(_1!) & Int(1 << 8) != 0 {_12 = reader.readInt32() }
var _13: [Api.MessageMedia]?
if Int(_1!) & Int(1 << 9) != 0 {if let _ = reader.readInt32() {
_13 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageMedia.self)
} }
var _14: Int32?
if Int(_1!) & Int(1 << 12) != 0 {_14 = reader.readInt32() }
var _15: Int32?
if Int(_1!) & Int(1 << 13) != 0 {_15 = reader.readInt32() }
var _16: Api.StarGift?
if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() {
_16 = Api.parse(reader, signature: signature) as? Api.StarGift
} }
var _17: Int32?
if Int(_1!) & Int(1 << 15) != 0 {_17 = reader.readInt32() }
var _18: Int32?
if Int(_1!) & Int(1 << 16) != 0 {_18 = reader.readInt32() }
var _19: Api.Peer?
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
_19 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _20: Api.StarsAmount?
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
_20 = Api.parse(reader, signature: signature) as? Api.StarsAmount
} }
var _21: Int32?
if Int(_1!) & Int(1 << 19) != 0 {_21 = reader.readInt32() }
var _22: Int32?
if Int(_1!) & Int(1 << 20) != 0 {_22 = reader.readInt32() }
var _23: Int32?
if Int(_1!) & Int(1 << 23) != 0 {_23 = reader.readInt32() }
var _24: Int32?
if Int(_1!) & Int(1 << 23) != 0 {_24 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 9) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 12) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 13) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 14) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 15) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 16) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 17) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 17) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 19) == 0) || _21 != nil
let _c22 = (Int(_1!) & Int(1 << 20) == 0) || _22 != nil
let _c23 = (Int(_1!) & Int(1 << 23) == 0) || _23 != nil
let _c24 = (Int(_1!) & Int(1 << 23) == 0) || _24 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 {
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, amount: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13, subscriptionPeriod: _14, giveawayPostId: _15, stargift: _16, floodskipNumber: _17, starrefCommissionPermille: _18, starrefPeer: _19, starrefAmount: _20, paidMessages: _21, premiumGiftMonths: _22, adsProceedsFromDate: _23, adsProceedsToDate: _24)
}
else {
return nil
}
}
}
}
public extension Api {
enum StarsTransactionPeer: TypeConstructorDescription {
case starsTransactionPeer(peer: Api.Peer)
case starsTransactionPeerAPI
case starsTransactionPeerAds
case starsTransactionPeerAppStore
case starsTransactionPeerFragment
case starsTransactionPeerPlayMarket
case starsTransactionPeerPremiumBot
case starsTransactionPeerUnsupported
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsTransactionPeer(let peer):
if boxed {
buffer.appendInt32(-670195363)
}
peer.serialize(buffer, true)
break
case .starsTransactionPeerAPI:
if boxed {
buffer.appendInt32(-110658899)
}
break
case .starsTransactionPeerAds:
if boxed {
buffer.appendInt32(1617438738)
}
break
case .starsTransactionPeerAppStore:
if boxed {
buffer.appendInt32(-1269320843)
}
break
case .starsTransactionPeerFragment:
if boxed {
buffer.appendInt32(-382740222)
}
break
case .starsTransactionPeerPlayMarket:
if boxed {
buffer.appendInt32(2069236235)
}
break
case .starsTransactionPeerPremiumBot:
if boxed {
buffer.appendInt32(621656824)
}
break
case .starsTransactionPeerUnsupported:
if boxed {
buffer.appendInt32(-1779253276)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsTransactionPeer(let peer):
return ("starsTransactionPeer", [("peer", peer as Any)])
case .starsTransactionPeerAPI:
return ("starsTransactionPeerAPI", [])
case .starsTransactionPeerAds:
return ("starsTransactionPeerAds", [])
case .starsTransactionPeerAppStore:
return ("starsTransactionPeerAppStore", [])
case .starsTransactionPeerFragment:
return ("starsTransactionPeerFragment", [])
case .starsTransactionPeerPlayMarket:
return ("starsTransactionPeerPlayMarket", [])
case .starsTransactionPeerPremiumBot:
return ("starsTransactionPeerPremiumBot", [])
case .starsTransactionPeerUnsupported:
return ("starsTransactionPeerUnsupported", [])
}
}
public static func parse_starsTransactionPeer(_ reader: BufferReader) -> StarsTransactionPeer? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
let _c1 = _1 != nil
if _c1 {
return Api.StarsTransactionPeer.starsTransactionPeer(peer: _1!)
}
else {
return nil
}
}
public static func parse_starsTransactionPeerAPI(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAPI
}
public static func parse_starsTransactionPeerAds(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAds
}
public static func parse_starsTransactionPeerAppStore(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAppStore
}
public static func parse_starsTransactionPeerFragment(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerFragment
}
public static func parse_starsTransactionPeerPlayMarket(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerPlayMarket
}
public static func parse_starsTransactionPeerPremiumBot(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerPremiumBot
}
public static func parse_starsTransactionPeerUnsupported(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerUnsupported
}
}
}

View file

@ -1,3 +1,271 @@
public extension Api {
enum StarsTransaction: TypeConstructorDescription {
case starsTransaction(flags: Int32, id: String, amount: Api.StarsAmount, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?, extendedMedia: [Api.MessageMedia]?, subscriptionPeriod: Int32?, giveawayPostId: Int32?, stargift: Api.StarGift?, floodskipNumber: Int32?, starrefCommissionPermille: Int32?, starrefPeer: Api.Peer?, starrefAmount: Api.StarsAmount?, paidMessages: Int32?, premiumGiftMonths: Int32?, adsProceedsFromDate: Int32?, adsProceedsToDate: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate):
if boxed {
buffer.appendInt32(325426864)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(id, buffer: buffer, boxed: false)
amount.serialize(buffer, true)
serializeInt32(date, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {serializeString(description!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
if Int(flags) & Int(1 << 5) != 0 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 5) != 0 {serializeString(transactionUrl!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 7) != 0 {serializeBytes(botPayload!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 8) != 0 {serializeInt32(msgId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 9) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(extendedMedia!.count))
for item in extendedMedia! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 12) != 0 {serializeInt32(subscriptionPeriod!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 13) != 0 {serializeInt32(giveawayPostId!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 14) != 0 {stargift!.serialize(buffer, true)}
if Int(flags) & Int(1 << 15) != 0 {serializeInt32(floodskipNumber!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 16) != 0 {serializeInt32(starrefCommissionPermille!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 17) != 0 {starrefPeer!.serialize(buffer, true)}
if Int(flags) & Int(1 << 17) != 0 {starrefAmount!.serialize(buffer, true)}
if Int(flags) & Int(1 << 19) != 0 {serializeInt32(paidMessages!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 20) != 0 {serializeInt32(premiumGiftMonths!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsFromDate!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 23) != 0 {serializeInt32(adsProceedsToDate!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsTransaction(let flags, let id, let amount, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId, let extendedMedia, let subscriptionPeriod, let giveawayPostId, let stargift, let floodskipNumber, let starrefCommissionPermille, let starrefPeer, let starrefAmount, let paidMessages, let premiumGiftMonths, let adsProceedsFromDate, let adsProceedsToDate):
return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("amount", amount as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any), ("botPayload", botPayload as Any), ("msgId", msgId as Any), ("extendedMedia", extendedMedia as Any), ("subscriptionPeriod", subscriptionPeriod as Any), ("giveawayPostId", giveawayPostId as Any), ("stargift", stargift as Any), ("floodskipNumber", floodskipNumber as Any), ("starrefCommissionPermille", starrefCommissionPermille as Any), ("starrefPeer", starrefPeer as Any), ("starrefAmount", starrefAmount as Any), ("paidMessages", paidMessages as Any), ("premiumGiftMonths", premiumGiftMonths as Any), ("adsProceedsFromDate", adsProceedsFromDate as Any), ("adsProceedsToDate", adsProceedsToDate as Any)])
}
}
public static func parse_starsTransaction(_ reader: BufferReader) -> StarsTransaction? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: Api.StarsAmount?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.StarsAmount
}
var _4: Int32?
_4 = reader.readInt32()
var _5: Api.StarsTransactionPeer?
if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.StarsTransactionPeer
}
var _6: String?
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
var _7: String?
if Int(_1!) & Int(1 << 1) != 0 {_7 = parseString(reader) }
var _8: Api.WebDocument?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_8 = Api.parse(reader, signature: signature) as? Api.WebDocument
} }
var _9: Int32?
if Int(_1!) & Int(1 << 5) != 0 {_9 = reader.readInt32() }
var _10: String?
if Int(_1!) & Int(1 << 5) != 0 {_10 = parseString(reader) }
var _11: Buffer?
if Int(_1!) & Int(1 << 7) != 0 {_11 = parseBytes(reader) }
var _12: Int32?
if Int(_1!) & Int(1 << 8) != 0 {_12 = reader.readInt32() }
var _13: [Api.MessageMedia]?
if Int(_1!) & Int(1 << 9) != 0 {if let _ = reader.readInt32() {
_13 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageMedia.self)
} }
var _14: Int32?
if Int(_1!) & Int(1 << 12) != 0 {_14 = reader.readInt32() }
var _15: Int32?
if Int(_1!) & Int(1 << 13) != 0 {_15 = reader.readInt32() }
var _16: Api.StarGift?
if Int(_1!) & Int(1 << 14) != 0 {if let signature = reader.readInt32() {
_16 = Api.parse(reader, signature: signature) as? Api.StarGift
} }
var _17: Int32?
if Int(_1!) & Int(1 << 15) != 0 {_17 = reader.readInt32() }
var _18: Int32?
if Int(_1!) & Int(1 << 16) != 0 {_18 = reader.readInt32() }
var _19: Api.Peer?
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
_19 = Api.parse(reader, signature: signature) as? Api.Peer
} }
var _20: Api.StarsAmount?
if Int(_1!) & Int(1 << 17) != 0 {if let signature = reader.readInt32() {
_20 = Api.parse(reader, signature: signature) as? Api.StarsAmount
} }
var _21: Int32?
if Int(_1!) & Int(1 << 19) != 0 {_21 = reader.readInt32() }
var _22: Int32?
if Int(_1!) & Int(1 << 20) != 0 {_22 = reader.readInt32() }
var _23: Int32?
if Int(_1!) & Int(1 << 23) != 0 {_23 = reader.readInt32() }
var _24: Int32?
if Int(_1!) & Int(1 << 23) != 0 {_24 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 9) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 12) == 0) || _14 != nil
let _c15 = (Int(_1!) & Int(1 << 13) == 0) || _15 != nil
let _c16 = (Int(_1!) & Int(1 << 14) == 0) || _16 != nil
let _c17 = (Int(_1!) & Int(1 << 15) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 16) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 17) == 0) || _19 != nil
let _c20 = (Int(_1!) & Int(1 << 17) == 0) || _20 != nil
let _c21 = (Int(_1!) & Int(1 << 19) == 0) || _21 != nil
let _c22 = (Int(_1!) & Int(1 << 20) == 0) || _22 != nil
let _c23 = (Int(_1!) & Int(1 << 23) == 0) || _23 != nil
let _c24 = (Int(_1!) & Int(1 << 23) == 0) || _24 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 {
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, amount: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12, extendedMedia: _13, subscriptionPeriod: _14, giveawayPostId: _15, stargift: _16, floodskipNumber: _17, starrefCommissionPermille: _18, starrefPeer: _19, starrefAmount: _20, paidMessages: _21, premiumGiftMonths: _22, adsProceedsFromDate: _23, adsProceedsToDate: _24)
}
else {
return nil
}
}
}
}
public extension Api {
enum StarsTransactionPeer: TypeConstructorDescription {
case starsTransactionPeer(peer: Api.Peer)
case starsTransactionPeerAPI
case starsTransactionPeerAds
case starsTransactionPeerAppStore
case starsTransactionPeerFragment
case starsTransactionPeerPlayMarket
case starsTransactionPeerPremiumBot
case starsTransactionPeerUnsupported
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starsTransactionPeer(let peer):
if boxed {
buffer.appendInt32(-670195363)
}
peer.serialize(buffer, true)
break
case .starsTransactionPeerAPI:
if boxed {
buffer.appendInt32(-110658899)
}
break
case .starsTransactionPeerAds:
if boxed {
buffer.appendInt32(1617438738)
}
break
case .starsTransactionPeerAppStore:
if boxed {
buffer.appendInt32(-1269320843)
}
break
case .starsTransactionPeerFragment:
if boxed {
buffer.appendInt32(-382740222)
}
break
case .starsTransactionPeerPlayMarket:
if boxed {
buffer.appendInt32(2069236235)
}
break
case .starsTransactionPeerPremiumBot:
if boxed {
buffer.appendInt32(621656824)
}
break
case .starsTransactionPeerUnsupported:
if boxed {
buffer.appendInt32(-1779253276)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starsTransactionPeer(let peer):
return ("starsTransactionPeer", [("peer", peer as Any)])
case .starsTransactionPeerAPI:
return ("starsTransactionPeerAPI", [])
case .starsTransactionPeerAds:
return ("starsTransactionPeerAds", [])
case .starsTransactionPeerAppStore:
return ("starsTransactionPeerAppStore", [])
case .starsTransactionPeerFragment:
return ("starsTransactionPeerFragment", [])
case .starsTransactionPeerPlayMarket:
return ("starsTransactionPeerPlayMarket", [])
case .starsTransactionPeerPremiumBot:
return ("starsTransactionPeerPremiumBot", [])
case .starsTransactionPeerUnsupported:
return ("starsTransactionPeerUnsupported", [])
}
}
public static func parse_starsTransactionPeer(_ reader: BufferReader) -> StarsTransactionPeer? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
let _c1 = _1 != nil
if _c1 {
return Api.StarsTransactionPeer.starsTransactionPeer(peer: _1!)
}
else {
return nil
}
}
public static func parse_starsTransactionPeerAPI(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAPI
}
public static func parse_starsTransactionPeerAds(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAds
}
public static func parse_starsTransactionPeerAppStore(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerAppStore
}
public static func parse_starsTransactionPeerFragment(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerFragment
}
public static func parse_starsTransactionPeerPlayMarket(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerPlayMarket
}
public static func parse_starsTransactionPeerPremiumBot(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerPremiumBot
}
public static func parse_starsTransactionPeerUnsupported(_ reader: BufferReader) -> StarsTransactionPeer? {
return Api.StarsTransactionPeer.starsTransactionPeerUnsupported
}
}
}
public extension Api {
enum StatsAbsValueAndPrev: TypeConstructorDescription {
case statsAbsValueAndPrev(current: Double, previous: Double)
@ -1024,369 +1292,3 @@ public extension Api {
}
}
public extension Api {
indirect enum StoryReaction: TypeConstructorDescription {
case storyReaction(peerId: Api.Peer, date: Int32, reaction: Api.Reaction)
case storyReactionPublicForward(message: Api.Message)
case storyReactionPublicRepost(peerId: Api.Peer, story: Api.StoryItem)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyReaction(let peerId, let date, let reaction):
if boxed {
buffer.appendInt32(1620104917)
}
peerId.serialize(buffer, true)
serializeInt32(date, buffer: buffer, boxed: false)
reaction.serialize(buffer, true)
break
case .storyReactionPublicForward(let message):
if boxed {
buffer.appendInt32(-1146411453)
}
message.serialize(buffer, true)
break
case .storyReactionPublicRepost(let peerId, let story):
if boxed {
buffer.appendInt32(-808644845)
}
peerId.serialize(buffer, true)
story.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyReaction(let peerId, let date, let reaction):
return ("storyReaction", [("peerId", peerId as Any), ("date", date as Any), ("reaction", reaction as Any)])
case .storyReactionPublicForward(let message):
return ("storyReactionPublicForward", [("message", message as Any)])
case .storyReactionPublicRepost(let peerId, let story):
return ("storyReactionPublicRepost", [("peerId", peerId as Any), ("story", story as Any)])
}
}
public static func parse_storyReaction(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Reaction?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Reaction
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.StoryReaction.storyReaction(peerId: _1!, date: _2!, reaction: _3!)
}
else {
return nil
}
}
public static func parse_storyReactionPublicForward(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Message?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Message
}
let _c1 = _1 != nil
if _c1 {
return Api.StoryReaction.storyReactionPublicForward(message: _1!)
}
else {
return nil
}
}
public static func parse_storyReactionPublicRepost(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: Api.StoryItem?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StoryItem
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StoryReaction.storyReactionPublicRepost(peerId: _1!, story: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum StoryView: TypeConstructorDescription {
case storyView(flags: Int32, userId: Int64, date: Int32, reaction: Api.Reaction?)
case storyViewPublicForward(flags: Int32, message: Api.Message)
case storyViewPublicRepost(flags: Int32, peerId: Api.Peer, story: Api.StoryItem)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyView(let flags, let userId, let date, let reaction):
if boxed {
buffer.appendInt32(-1329730875)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {reaction!.serialize(buffer, true)}
break
case .storyViewPublicForward(let flags, let message):
if boxed {
buffer.appendInt32(-1870436597)
}
serializeInt32(flags, buffer: buffer, boxed: false)
message.serialize(buffer, true)
break
case .storyViewPublicRepost(let flags, let peerId, let story):
if boxed {
buffer.appendInt32(-1116418231)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peerId.serialize(buffer, true)
story.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyView(let flags, let userId, let date, let reaction):
return ("storyView", [("flags", flags as Any), ("userId", userId as Any), ("date", date as Any), ("reaction", reaction as Any)])
case .storyViewPublicForward(let flags, let message):
return ("storyViewPublicForward", [("flags", flags as Any), ("message", message as Any)])
case .storyViewPublicRepost(let flags, let peerId, let story):
return ("storyViewPublicRepost", [("flags", flags as Any), ("peerId", peerId as Any), ("story", story as Any)])
}
}
public static func parse_storyView(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
var _4: Api.Reaction?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Reaction
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.StoryView.storyView(flags: _1!, userId: _2!, date: _3!, reaction: _4)
}
else {
return nil
}
}
public static func parse_storyViewPublicForward(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Message?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Message
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StoryView.storyViewPublicForward(flags: _1!, message: _2!)
}
else {
return nil
}
}
public static func parse_storyViewPublicRepost(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Api.StoryItem?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.StoryItem
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.StoryView.storyViewPublicRepost(flags: _1!, peerId: _2!, story: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum StoryViews: TypeConstructorDescription {
case storyViews(flags: Int32, viewsCount: Int32, forwardsCount: Int32?, reactions: [Api.ReactionCount]?, reactionsCount: Int32?, recentViewers: [Int64]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViews(let flags, let viewsCount, let forwardsCount, let reactions, let reactionsCount, let recentViewers):
if boxed {
buffer.appendInt32(-1923523370)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(viewsCount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(forwardsCount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(reactions!.count))
for item in reactions! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(reactionsCount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentViewers!.count))
for item in recentViewers! {
serializeInt64(item, buffer: buffer, boxed: false)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViews(let flags, let viewsCount, let forwardsCount, let reactions, let reactionsCount, let recentViewers):
return ("storyViews", [("flags", flags as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactions", reactions as Any), ("reactionsCount", reactionsCount as Any), ("recentViewers", recentViewers as Any)])
}
}
public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() }
var _4: [Api.ReactionCount]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ReactionCount.self)
} }
var _5: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt32() }
var _6: [Int64]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.StoryViews.storyViews(flags: _1!, viewsCount: _2!, forwardsCount: _3, reactions: _4, reactionsCount: _5, recentViewers: _6)
}
else {
return nil
}
}
}
}
public extension Api {
enum SuggestedPost: TypeConstructorDescription {
case suggestedPost(flags: Int32, price: Api.StarsAmount?, scheduleDate: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .suggestedPost(let flags, let price, let scheduleDate):
if boxed {
buffer.appendInt32(244201445)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {price!.serialize(buffer, true)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .suggestedPost(let flags, let price, let scheduleDate):
return ("suggestedPost", [("flags", flags as Any), ("price", price as Any), ("scheduleDate", scheduleDate as Any)])
}
}
public static func parse_suggestedPost(_ reader: BufferReader) -> SuggestedPost? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.StarsAmount?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarsAmount
} }
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 3) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.SuggestedPost.suggestedPost(flags: _1!, price: _2, scheduleDate: _3)
}
else {
return nil
}
}
}
}
public extension Api {
enum TextWithEntities: TypeConstructorDescription {
case textWithEntities(text: String, entities: [Api.MessageEntity])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .textWithEntities(let text, let entities):
if boxed {
buffer.appendInt32(1964978502)
}
serializeString(text, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities.count))
for item in entities {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .textWithEntities(let text, let entities):
return ("textWithEntities", [("text", text as Any), ("entities", entities as Any)])
}
}
public static func parse_textWithEntities(_ reader: BufferReader) -> TextWithEntities? {
var _1: String?
_1 = parseString(reader)
var _2: [Api.MessageEntity]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.TextWithEntities.textWithEntities(text: _1!, entities: _2!)
}
else {
return nil
}
}
}
}

View file

@ -1,3 +1,369 @@
public extension Api {
indirect enum StoryReaction: TypeConstructorDescription {
case storyReaction(peerId: Api.Peer, date: Int32, reaction: Api.Reaction)
case storyReactionPublicForward(message: Api.Message)
case storyReactionPublicRepost(peerId: Api.Peer, story: Api.StoryItem)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyReaction(let peerId, let date, let reaction):
if boxed {
buffer.appendInt32(1620104917)
}
peerId.serialize(buffer, true)
serializeInt32(date, buffer: buffer, boxed: false)
reaction.serialize(buffer, true)
break
case .storyReactionPublicForward(let message):
if boxed {
buffer.appendInt32(-1146411453)
}
message.serialize(buffer, true)
break
case .storyReactionPublicRepost(let peerId, let story):
if boxed {
buffer.appendInt32(-808644845)
}
peerId.serialize(buffer, true)
story.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyReaction(let peerId, let date, let reaction):
return ("storyReaction", [("peerId", peerId as Any), ("date", date as Any), ("reaction", reaction as Any)])
case .storyReactionPublicForward(let message):
return ("storyReactionPublicForward", [("message", message as Any)])
case .storyReactionPublicRepost(let peerId, let story):
return ("storyReactionPublicRepost", [("peerId", peerId as Any), ("story", story as Any)])
}
}
public static func parse_storyReaction(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: Int32?
_2 = reader.readInt32()
var _3: Api.Reaction?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.Reaction
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.StoryReaction.storyReaction(peerId: _1!, date: _2!, reaction: _3!)
}
else {
return nil
}
}
public static func parse_storyReactionPublicForward(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Message?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Message
}
let _c1 = _1 != nil
if _c1 {
return Api.StoryReaction.storyReactionPublicForward(message: _1!)
}
else {
return nil
}
}
public static func parse_storyReactionPublicRepost(_ reader: BufferReader) -> StoryReaction? {
var _1: Api.Peer?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _2: Api.StoryItem?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StoryItem
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StoryReaction.storyReactionPublicRepost(peerId: _1!, story: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
indirect enum StoryView: TypeConstructorDescription {
case storyView(flags: Int32, userId: Int64, date: Int32, reaction: Api.Reaction?)
case storyViewPublicForward(flags: Int32, message: Api.Message)
case storyViewPublicRepost(flags: Int32, peerId: Api.Peer, story: Api.StoryItem)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyView(let flags, let userId, let date, let reaction):
if boxed {
buffer.appendInt32(-1329730875)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false)
serializeInt32(date, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {reaction!.serialize(buffer, true)}
break
case .storyViewPublicForward(let flags, let message):
if boxed {
buffer.appendInt32(-1870436597)
}
serializeInt32(flags, buffer: buffer, boxed: false)
message.serialize(buffer, true)
break
case .storyViewPublicRepost(let flags, let peerId, let story):
if boxed {
buffer.appendInt32(-1116418231)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peerId.serialize(buffer, true)
story.serialize(buffer, true)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyView(let flags, let userId, let date, let reaction):
return ("storyView", [("flags", flags as Any), ("userId", userId as Any), ("date", date as Any), ("reaction", reaction as Any)])
case .storyViewPublicForward(let flags, let message):
return ("storyViewPublicForward", [("flags", flags as Any), ("message", message as Any)])
case .storyViewPublicRepost(let flags, let peerId, let story):
return ("storyViewPublicRepost", [("flags", flags as Any), ("peerId", peerId as Any), ("story", story as Any)])
}
}
public static func parse_storyView(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
var _4: Api.Reaction?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.Reaction
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.StoryView.storyView(flags: _1!, userId: _2!, date: _3!, reaction: _4)
}
else {
return nil
}
}
public static func parse_storyViewPublicForward(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Message?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Message
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StoryView.storyViewPublicForward(flags: _1!, message: _2!)
}
else {
return nil
}
}
public static func parse_storyViewPublicRepost(_ reader: BufferReader) -> StoryView? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Peer?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.Peer
}
var _3: Api.StoryItem?
if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.StoryItem
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.StoryView.storyViewPublicRepost(flags: _1!, peerId: _2!, story: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum StoryViews: TypeConstructorDescription {
case storyViews(flags: Int32, viewsCount: Int32, forwardsCount: Int32?, reactions: [Api.ReactionCount]?, reactionsCount: Int32?, recentViewers: [Int64]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .storyViews(let flags, let viewsCount, let forwardsCount, let reactions, let reactionsCount, let recentViewers):
if boxed {
buffer.appendInt32(-1923523370)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(viewsCount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {serializeInt32(forwardsCount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(reactions!.count))
for item in reactions! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(reactionsCount!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentViewers!.count))
for item in recentViewers! {
serializeInt64(item, buffer: buffer, boxed: false)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .storyViews(let flags, let viewsCount, let forwardsCount, let reactions, let reactionsCount, let recentViewers):
return ("storyViews", [("flags", flags as Any), ("viewsCount", viewsCount as Any), ("forwardsCount", forwardsCount as Any), ("reactions", reactions as Any), ("reactionsCount", reactionsCount as Any), ("recentViewers", recentViewers as Any)])
}
}
public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() }
var _4: [Api.ReactionCount]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ReactionCount.self)
} }
var _5: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt32() }
var _6: [Int64]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.StoryViews.storyViews(flags: _1!, viewsCount: _2!, forwardsCount: _3, reactions: _4, reactionsCount: _5, recentViewers: _6)
}
else {
return nil
}
}
}
}
public extension Api {
enum SuggestedPost: TypeConstructorDescription {
case suggestedPost(flags: Int32, price: Api.StarsAmount?, scheduleDate: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .suggestedPost(let flags, let price, let scheduleDate):
if boxed {
buffer.appendInt32(244201445)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {price!.serialize(buffer, true)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .suggestedPost(let flags, let price, let scheduleDate):
return ("suggestedPost", [("flags", flags as Any), ("price", price as Any), ("scheduleDate", scheduleDate as Any)])
}
}
public static func parse_suggestedPost(_ reader: BufferReader) -> SuggestedPost? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.StarsAmount?
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarsAmount
} }
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 3) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.SuggestedPost.suggestedPost(flags: _1!, price: _2, scheduleDate: _3)
}
else {
return nil
}
}
}
}
public extension Api {
enum TextWithEntities: TypeConstructorDescription {
case textWithEntities(text: String, entities: [Api.MessageEntity])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .textWithEntities(let text, let entities):
if boxed {
buffer.appendInt32(1964978502)
}
serializeString(text, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities.count))
for item in entities {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .textWithEntities(let text, let entities):
return ("textWithEntities", [("text", text as Any), ("entities", entities as Any)])
}
}
public static func parse_textWithEntities(_ reader: BufferReader) -> TextWithEntities? {
var _1: String?
_1 = parseString(reader)
var _2: [Api.MessageEntity]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.TextWithEntities.textWithEntities(text: _1!, entities: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
enum Theme: TypeConstructorDescription {
case theme(flags: Int32, id: Int64, accessHash: Int64, slug: String, title: String, document: Api.Document?, settings: [Api.ThemeSettings]?, emoticon: String?, installsCount: Int32?)
@ -675,6 +1041,8 @@ public extension Api {
case updateSentStoryReaction(peer: Api.Peer, storyId: Int32, reaction: Api.Reaction)
case updateServiceNotification(flags: Int32, inboxDate: Int32?, type: String, message: String, media: Api.MessageMedia, entities: [Api.MessageEntity])
case updateSmsJob(jobId: String)
case updateStarGiftAuctionState(giftId: Int64, state: Api.StarGiftAuctionState)
case updateStarGiftAuctionUserState(giftId: Int64, userState: Api.StarGiftAuctionUserState)
case updateStarsBalance(balance: Api.StarsAmount)
case updateStarsRevenueStatus(peer: Api.Peer, status: Api.StarsRevenueStatus)
case updateStickerSets(flags: Int32)
@ -1864,6 +2232,20 @@ public extension Api {
}
serializeString(jobId, buffer: buffer, boxed: false)
break
case .updateStarGiftAuctionState(let giftId, let state):
if boxed {
buffer.appendInt32(1222788802)
}
serializeInt64(giftId, buffer: buffer, boxed: false)
state.serialize(buffer, true)
break
case .updateStarGiftAuctionUserState(let giftId, let userState):
if boxed {
buffer.appendInt32(-598150370)
}
serializeInt64(giftId, buffer: buffer, boxed: false)
userState.serialize(buffer, true)
break
case .updateStarsBalance(let balance):
if boxed {
buffer.appendInt32(1317053305)
@ -2260,6 +2642,10 @@ public extension Api {
return ("updateServiceNotification", [("flags", flags as Any), ("inboxDate", inboxDate as Any), ("type", type as Any), ("message", message as Any), ("media", media as Any), ("entities", entities as Any)])
case .updateSmsJob(let jobId):
return ("updateSmsJob", [("jobId", jobId as Any)])
case .updateStarGiftAuctionState(let giftId, let state):
return ("updateStarGiftAuctionState", [("giftId", giftId as Any), ("state", state as Any)])
case .updateStarGiftAuctionUserState(let giftId, let userState):
return ("updateStarGiftAuctionUserState", [("giftId", giftId as Any), ("userState", userState as Any)])
case .updateStarsBalance(let balance):
return ("updateStarsBalance", [("balance", balance as Any)])
case .updateStarsRevenueStatus(let peer, let status):
@ -4679,6 +5065,38 @@ public extension Api {
return nil
}
}
public static func parse_updateStarGiftAuctionState(_ reader: BufferReader) -> Update? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Api.StarGiftAuctionState?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarGiftAuctionState
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updateStarGiftAuctionState(giftId: _1!, state: _2!)
}
else {
return nil
}
}
public static func parse_updateStarGiftAuctionUserState(_ reader: BufferReader) -> Update? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Api.StarGiftAuctionUserState?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarGiftAuctionUserState
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updateStarGiftAuctionUserState(giftId: _1!, userState: _2!)
}
else {
return nil
}
}
public static func parse_updateStarsBalance(_ reader: BufferReader) -> Update? {
var _1: Api.StarsAmount?
if let signature = reader.readInt32() {

View file

@ -1,3 +1,49 @@
public extension Api {
enum BusinessGreetingMessage: TypeConstructorDescription {
case businessGreetingMessage(shortcutId: Int32, recipients: Api.BusinessRecipients, noActivityDays: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
if boxed {
buffer.appendInt32(-451302485)
}
serializeInt32(shortcutId, buffer: buffer, boxed: false)
recipients.serialize(buffer, true)
serializeInt32(noActivityDays, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .businessGreetingMessage(let shortcutId, let recipients, let noActivityDays):
return ("businessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)])
}
}
public static func parse_businessGreetingMessage(_ reader: BufferReader) -> BusinessGreetingMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.BusinessRecipients?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.BusinessRecipients
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.BusinessGreetingMessage.businessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!)
}
else {
return nil
}
}
}
}
public extension Api {
enum BusinessIntro: TypeConstructorDescription {
case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?)

View file

@ -276,6 +276,64 @@ public extension Api.payments {
}
}
public extension Api.payments {
enum StarGiftAuctionState: TypeConstructorDescription {
case starGiftAuctionState(state: Api.StarGiftAuctionState, userState: Api.StarGiftAuctionUserState, timeout: Int32, users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .starGiftAuctionState(let state, let userState, let timeout, let users):
if boxed {
buffer.appendInt32(-2061303084)
}
state.serialize(buffer, true)
userState.serialize(buffer, true)
serializeInt32(timeout, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .starGiftAuctionState(let state, let userState, let timeout, let users):
return ("starGiftAuctionState", [("state", state as Any), ("userState", userState as Any), ("timeout", timeout as Any), ("users", users as Any)])
}
}
public static func parse_starGiftAuctionState(_ reader: BufferReader) -> StarGiftAuctionState? {
var _1: Api.StarGiftAuctionState?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.StarGiftAuctionState
}
var _2: Api.StarGiftAuctionUserState?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.StarGiftAuctionUserState
}
var _3: Int32?
_3 = reader.readInt32()
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.payments.StarGiftAuctionState.starGiftAuctionState(state: _1!, userState: _2!, timeout: _3!, users: _4!)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum StarGiftCollections: TypeConstructorDescription {
case starGiftCollections(collections: [Api.StarGiftCollection])
@ -1630,89 +1688,3 @@ public extension Api.premium {
}
}
public extension Api.premium {
enum BoostsStatus: TypeConstructorDescription {
case boostsStatus(flags: Int32, level: Int32, currentLevelBoosts: Int32, boosts: Int32, giftBoosts: Int32?, nextLevelBoosts: Int32?, premiumAudience: Api.StatsPercentValue?, boostUrl: String, prepaidGiveaways: [Api.PrepaidGiveaway]?, myBoostSlots: [Int32]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let giftBoosts, let nextLevelBoosts, let premiumAudience, let boostUrl, let prepaidGiveaways, let myBoostSlots):
if boxed {
buffer.appendInt32(1230586490)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(level, buffer: buffer, boxed: false)
serializeInt32(currentLevelBoosts, buffer: buffer, boxed: false)
serializeInt32(boosts, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(giftBoosts!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextLevelBoosts!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {premiumAudience!.serialize(buffer, true)}
serializeString(boostUrl, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(prepaidGiveaways!.count))
for item in prepaidGiveaways! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(myBoostSlots!.count))
for item in myBoostSlots! {
serializeInt32(item, buffer: buffer, boxed: false)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let giftBoosts, let nextLevelBoosts, let premiumAudience, let boostUrl, let prepaidGiveaways, let myBoostSlots):
return ("boostsStatus", [("flags", flags as Any), ("level", level as Any), ("currentLevelBoosts", currentLevelBoosts as Any), ("boosts", boosts as Any), ("giftBoosts", giftBoosts as Any), ("nextLevelBoosts", nextLevelBoosts as Any), ("premiumAudience", premiumAudience as Any), ("boostUrl", boostUrl as Any), ("prepaidGiveaways", prepaidGiveaways as Any), ("myBoostSlots", myBoostSlots as Any)])
}
}
public static func parse_boostsStatus(_ reader: BufferReader) -> BoostsStatus? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt32() }
var _7: Api.StatsPercentValue?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue
} }
var _8: String?
_8 = parseString(reader)
var _9: [Api.PrepaidGiveaway]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrepaidGiveaway.self)
} }
var _10: [Int32]?
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
_10 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 2) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.premium.BoostsStatus.boostsStatus(flags: _1!, level: _2!, currentLevelBoosts: _3!, boosts: _4!, giftBoosts: _5, nextLevelBoosts: _6, premiumAudience: _7, boostUrl: _8!, prepaidGiveaways: _9, myBoostSlots: _10)
}
else {
return nil
}
}
}
}

View file

@ -1,3 +1,89 @@
public extension Api.premium {
enum BoostsStatus: TypeConstructorDescription {
case boostsStatus(flags: Int32, level: Int32, currentLevelBoosts: Int32, boosts: Int32, giftBoosts: Int32?, nextLevelBoosts: Int32?, premiumAudience: Api.StatsPercentValue?, boostUrl: String, prepaidGiveaways: [Api.PrepaidGiveaway]?, myBoostSlots: [Int32]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let giftBoosts, let nextLevelBoosts, let premiumAudience, let boostUrl, let prepaidGiveaways, let myBoostSlots):
if boxed {
buffer.appendInt32(1230586490)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(level, buffer: buffer, boxed: false)
serializeInt32(currentLevelBoosts, buffer: buffer, boxed: false)
serializeInt32(boosts, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 4) != 0 {serializeInt32(giftBoosts!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextLevelBoosts!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 1) != 0 {premiumAudience!.serialize(buffer, true)}
serializeString(boostUrl, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(prepaidGiveaways!.count))
for item in prepaidGiveaways! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(myBoostSlots!.count))
for item in myBoostSlots! {
serializeInt32(item, buffer: buffer, boxed: false)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .boostsStatus(let flags, let level, let currentLevelBoosts, let boosts, let giftBoosts, let nextLevelBoosts, let premiumAudience, let boostUrl, let prepaidGiveaways, let myBoostSlots):
return ("boostsStatus", [("flags", flags as Any), ("level", level as Any), ("currentLevelBoosts", currentLevelBoosts as Any), ("boosts", boosts as Any), ("giftBoosts", giftBoosts as Any), ("nextLevelBoosts", nextLevelBoosts as Any), ("premiumAudience", premiumAudience as Any), ("boostUrl", boostUrl as Any), ("prepaidGiveaways", prepaidGiveaways as Any), ("myBoostSlots", myBoostSlots as Any)])
}
}
public static func parse_boostsStatus(_ reader: BufferReader) -> BoostsStatus? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: Int32?
_3 = reader.readInt32()
var _4: Int32?
_4 = reader.readInt32()
var _5: Int32?
if Int(_1!) & Int(1 << 4) != 0 {_5 = reader.readInt32() }
var _6: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt32() }
var _7: Api.StatsPercentValue?
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue
} }
var _8: String?
_8 = parseString(reader)
var _9: [Api.PrepaidGiveaway]?
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
_9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrepaidGiveaway.self)
} }
var _10: [Int32]?
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
_10 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil
let _c8 = _8 != nil
let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil
let _c10 = (Int(_1!) & Int(1 << 2) == 0) || _10 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
return Api.premium.BoostsStatus.boostsStatus(flags: _1!, level: _2!, currentLevelBoosts: _3!, boosts: _4!, giftBoosts: _5, nextLevelBoosts: _6, premiumAudience: _7, boostUrl: _8!, prepaidGiveaways: _9, myBoostSlots: _10)
}
else {
return nil
}
}
}
}
public extension Api.premium {
enum MyBoosts: TypeConstructorDescription {
case myBoosts(myBoosts: [Api.MyBoost], chats: [Api.Chat], users: [Api.User])

View file

@ -9754,6 +9754,22 @@ public extension Api.functions.payments {
})
}
}
public extension Api.functions.payments {
static func getStarGiftAuctionState(giftId: Int64, version: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.StarGiftAuctionState>) {
let buffer = Buffer()
buffer.appendInt32(1352689229)
serializeInt64(giftId, buffer: buffer, boxed: false)
serializeInt32(version, buffer: buffer, boxed: false)
return (FunctionDescription(name: "payments.getStarGiftAuctionState", parameters: [("giftId", String(describing: giftId)), ("version", String(describing: version))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.StarGiftAuctionState? in
let reader = BufferReader(buffer)
var result: Api.payments.StarGiftAuctionState?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.payments.StarGiftAuctionState
}
return result
})
}
}
public extension Api.functions.payments {
static func getStarGiftCollections(peer: Api.InputPeer, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.StarGiftCollections>) {
let buffer = Buffer()
@ -10854,6 +10870,22 @@ public extension Api.functions.phone {
})
}
}
public extension Api.functions.phone {
static func saveDefaultSendAs(call: Api.InputGroupCall, sendAs: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(1097313745)
call.serialize(buffer, true)
sendAs.serialize(buffer, true)
return (FunctionDescription(name: "phone.saveDefaultSendAs", parameters: [("call", String(describing: call)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.phone {
static func sendConferenceCallBroadcast(call: Api.InputGroupCall, block: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
@ -10887,15 +10919,16 @@ public extension Api.functions.phone {
}
}
public extension Api.functions.phone {
static func sendGroupCallMessage(flags: Int32, call: Api.InputGroupCall, randomId: Int64, message: Api.TextWithEntities, allowPaidStars: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
static func sendGroupCallMessage(flags: Int32, call: Api.InputGroupCall, randomId: Int64, message: Api.TextWithEntities, allowPaidStars: Int64?, sendAs: Api.InputPeer?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(445465039)
buffer.appendInt32(-1311697904)
serializeInt32(flags, buffer: buffer, boxed: false)
call.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
message.serialize(buffer, true)
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(allowPaidStars!, buffer: buffer, boxed: false)}
return (FunctionDescription(name: "phone.sendGroupCallMessage", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("randomId", String(describing: randomId)), ("message", String(describing: message)), ("allowPaidStars", String(describing: allowPaidStars))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
if Int(flags) & Int(1 << 1) != 0 {sendAs!.serialize(buffer, true)}
return (FunctionDescription(name: "phone.sendGroupCallMessage", parameters: [("flags", String(describing: flags)), ("call", String(describing: call)), ("randomId", String(describing: randomId)), ("message", String(describing: message)), ("allowPaidStars", String(describing: allowPaidStars)), ("sendAs", String(describing: sendAs))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {

View file

@ -1222,14 +1222,14 @@ public extension Api {
}
public extension Api {
enum GroupCall: TypeConstructorDescription {
case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, unmutedVideoCount: Int32?, unmutedVideoLimit: Int32, version: Int32, inviteLink: String?, sendPaidMessagesStars: Int64?)
case groupCall(flags: Int32, id: Int64, accessHash: Int64, participantsCount: Int32, title: String?, streamDcId: Int32?, recordStartDate: Int32?, scheduleDate: Int32?, unmutedVideoCount: Int32?, unmutedVideoLimit: Int32, version: Int32, inviteLink: String?, sendPaidMessagesStars: Int64?, defaultSendAs: Api.Peer?)
case groupCallDiscarded(id: Int64, accessHash: Int64, duration: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars):
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars, let defaultSendAs):
if boxed {
buffer.appendInt32(-674602536)
buffer.appendInt32(-273500649)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false)
@ -1244,6 +1244,7 @@ public extension Api {
serializeInt32(version, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 16) != 0 {serializeString(inviteLink!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 20) != 0 {serializeInt64(sendPaidMessagesStars!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 21) != 0 {defaultSendAs!.serialize(buffer, true)}
break
case .groupCallDiscarded(let id, let accessHash, let duration):
if boxed {
@ -1258,8 +1259,8 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars):
return ("groupCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("participantsCount", participantsCount as Any), ("title", title as Any), ("streamDcId", streamDcId as Any), ("recordStartDate", recordStartDate as Any), ("scheduleDate", scheduleDate as Any), ("unmutedVideoCount", unmutedVideoCount as Any), ("unmutedVideoLimit", unmutedVideoLimit as Any), ("version", version as Any), ("inviteLink", inviteLink as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any)])
case .groupCall(let flags, let id, let accessHash, let participantsCount, let title, let streamDcId, let recordStartDate, let scheduleDate, let unmutedVideoCount, let unmutedVideoLimit, let version, let inviteLink, let sendPaidMessagesStars, let defaultSendAs):
return ("groupCall", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("participantsCount", participantsCount as Any), ("title", title as Any), ("streamDcId", streamDcId as Any), ("recordStartDate", recordStartDate as Any), ("scheduleDate", scheduleDate as Any), ("unmutedVideoCount", unmutedVideoCount as Any), ("unmutedVideoLimit", unmutedVideoLimit as Any), ("version", version as Any), ("inviteLink", inviteLink as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("defaultSendAs", defaultSendAs as Any)])
case .groupCallDiscarded(let id, let accessHash, let duration):
return ("groupCallDiscarded", [("id", id as Any), ("accessHash", accessHash as Any), ("duration", duration as Any)])
}
@ -1292,6 +1293,10 @@ public extension Api {
if Int(_1!) & Int(1 << 16) != 0 {_12 = parseString(reader) }
var _13: Int64?
if Int(_1!) & Int(1 << 20) != 0 {_13 = reader.readInt64() }
var _14: Api.Peer?
if Int(_1!) & Int(1 << 21) != 0 {if let signature = reader.readInt32() {
_14 = Api.parse(reader, signature: signature) as? Api.Peer
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -1305,8 +1310,9 @@ public extension Api {
let _c11 = _11 != nil
let _c12 = (Int(_1!) & Int(1 << 16) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 20) == 0) || _13 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 {
return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, title: _5, streamDcId: _6, recordStartDate: _7, scheduleDate: _8, unmutedVideoCount: _9, unmutedVideoLimit: _10!, version: _11!, inviteLink: _12, sendPaidMessagesStars: _13)
let _c14 = (Int(_1!) & Int(1 << 21) == 0) || _14 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
return Api.GroupCall.groupCall(flags: _1!, id: _2!, accessHash: _3!, participantsCount: _4!, title: _5, streamDcId: _6, recordStartDate: _7, scheduleDate: _8, unmutedVideoCount: _9, unmutedVideoLimit: _10!, version: _11!, inviteLink: _12, sendPaidMessagesStars: _13, defaultSendAs: _14)
}
else {
return nil

View file

@ -520,7 +520,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
}
#if DEBUG
if data.info.isStream {
if data.info.isStream, !"".isEmpty {
if self.imageDisposable == nil {
let engine = self.context.engine
let info = data.info

View file

@ -3330,6 +3330,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
})
}
public func addExternalAudioData(data: Data) {
self.genericCallContext?.addExternalAudioData(data: data)
}
public func requestVideo() {
if self.videoCapturer == nil {
let videoCapturer = OngoingCallVideoCapturer()

View file

@ -137,6 +137,8 @@ enum AccountStateMutationOperation {
case UpdateStarsReactionsDefaultPrivacy(privacy: TelegramPaidReactionPrivacy)
case ReportMessageDelivery([MessageId])
case UpdateMonoForumNoPaidException(peerId: PeerId, threadId: Int64, isFree: Bool)
case UpdateStarGiftAuctionState(giftId: Int64, state: GiftAuctionContext.State.AuctionState)
case UpdateStarGiftAuctionMyState(giftId: Int64, state: GiftAuctionContext.State.MyState)
}
struct HoleFromPreviousState {
@ -727,9 +729,17 @@ struct AccountMutableState {
self.addOperation(.UpdateMonoForumNoPaidException(peerId: peerId, threadId: threadId, isFree: isFree))
}
mutating func updateStarGiftAuctionState(giftId: Int64, state: GiftAuctionContext.State.AuctionState) {
self.addOperation(.UpdateStarGiftAuctionState(giftId: giftId, state: state))
}
mutating func updateStarGiftAuctionMyState(giftId: Int64, state: GiftAuctionContext.State.MyState) {
self.addOperation(.UpdateStarGiftAuctionMyState(giftId: giftId, state: state))
}
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateGroupCallMessage, .UpdateGroupCallOpaqueMessage, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateGroupCallMessage, .UpdateGroupCallOpaqueMessage, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException, .UpdateStarGiftAuctionState, .UpdateStarGiftAuctionMyState:
break
case let .AddMessages(messages, location):
for message in messages {
@ -880,6 +890,8 @@ struct AccountReplayedFinalState {
let sentScheduledMessageIds: Set<MessageId>
let reportMessageDelivery: Set<MessageId>
let addedConferenceInvitationMessagesIds: [MessageId]
let updatedStarGiftAuctionState: [Int64: GiftAuctionContext.State.AuctionState]
let updatedStarGiftAuctionMyState: [Int64: GiftAuctionContext.State.MyState]
}
struct AccountFinalStateEvents {
@ -913,12 +925,14 @@ struct AccountFinalStateEvents {
let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances]
let reportMessageDelivery: Set<MessageId>
let addedConferenceInvitationMessagesIds: [MessageId]
let updatedStarGiftAuctionState: [Int64: GiftAuctionContext.State.AuctionState]
let updatedStarGiftAuctionMyState: [Int64: GiftAuctionContext.State.MyState]
var isEmpty: Bool {
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.groupCallMessageUpdates.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedStarsBalance.isEmpty && self.updatedTonBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty && self.reportMessageDelivery.isEmpty && self.addedConferenceInvitationMessagesIds.isEmpty
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.groupCallMessageUpdates.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedStarsBalance.isEmpty && self.updatedTonBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty && self.reportMessageDelivery.isEmpty && self.addedConferenceInvitationMessagesIds.isEmpty && self.updatedStarGiftAuctionState.isEmpty && self.updatedStarGiftAuctionMyState.isEmpty
}
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], groupCallMessageUpdates: [GroupCallMessageUpdate] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedTonBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set<MessageId> = Set(), reportMessageDelivery: Set<MessageId> = Set(), addedConferenceInvitationMessagesIds: [MessageId] = []) {
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], groupCallMessageUpdates: [GroupCallMessageUpdate] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [PeerAndBoundThreadId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedTonBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set<MessageId> = Set(), reportMessageDelivery: Set<MessageId> = Set(), addedConferenceInvitationMessagesIds: [MessageId] = [], updatedStarGiftAuctionState: [Int64: GiftAuctionContext.State.AuctionState] = [:], updatedStarGiftAuctionMyState: [Int64: GiftAuctionContext.State.MyState] = [:]) {
self.addedIncomingMessageIds = addedIncomingMessageIds
self.addedReactionEvents = addedReactionEvents
self.wasScheduledMessageIds = wasScheduledMessageIds
@ -949,6 +963,8 @@ struct AccountFinalStateEvents {
self.sentScheduledMessageIds = sentScheduledMessageIds
self.reportMessageDelivery = reportMessageDelivery
self.addedConferenceInvitationMessagesIds = addedConferenceInvitationMessagesIds
self.updatedStarGiftAuctionState = updatedStarGiftAuctionState
self.updatedStarGiftAuctionMyState = updatedStarGiftAuctionMyState
}
init(state: AccountReplayedFinalState) {
@ -982,6 +998,8 @@ struct AccountFinalStateEvents {
self.sentScheduledMessageIds = state.sentScheduledMessageIds
self.reportMessageDelivery = state.reportMessageDelivery
self.addedConferenceInvitationMessagesIds = state.addedConferenceInvitationMessagesIds
self.updatedStarGiftAuctionState = state.updatedStarGiftAuctionState
self.updatedStarGiftAuctionMyState = state.updatedStarGiftAuctionMyState
}
func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents {
@ -1040,7 +1058,7 @@ struct AccountFinalStateEvents {
updatedQts: updatedQts,
externallyUpdatedPeerId: externallyUpdatedPeerId,
authorizationListUpdated: authorizationListUpdated,
updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates,uniquingKeysWith: { lhs, _ in lhs }),
updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }),
updateConfig: updateConfig,
isPremiumUpdated: isPremiumUpdated,
updatedStarsBalance: self.updatedStarsBalance.merging(other.updatedStarsBalance, uniquingKeysWith: { lhs, _ in lhs }),
@ -1048,7 +1066,9 @@ struct AccountFinalStateEvents {
updatedStarsRevenueStatus: self.updatedStarsRevenueStatus.merging(other.updatedStarsRevenueStatus, uniquingKeysWith: { lhs, _ in lhs }),
sentScheduledMessageIds: sentScheduledMessageIds,
reportMessageDelivery: reportMessageDelivery,
addedConferenceInvitationMessagesIds: addedConferenceInvitationMessagesIds
addedConferenceInvitationMessagesIds: addedConferenceInvitationMessagesIds,
updatedStarGiftAuctionState: self.updatedStarGiftAuctionState.merging(other.updatedStarGiftAuctionState, uniquingKeysWith: { lhs, _ in lhs }),
updatedStarGiftAuctionMyState: self.updatedStarGiftAuctionMyState.merging(other.updatedStarGiftAuctionMyState, uniquingKeysWith: { lhs, _ in lhs })
)
}
}

View file

@ -111,7 +111,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .joinedByRequest)
case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text):
return TelegramMediaAction(action: .webViewData(text))
case let .messageActionGiftPremium(_, currency, amount, months, cryptoCurrency, cryptoAmount, message):
case let .messageActionGiftPremium(_, currency, amount, days, cryptoCurrency, cryptoAmount, message):
let text: String?
let entities: [MessageTextEntity]?
switch message {
@ -122,7 +122,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
text = nil
entities = nil
}
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, text: text, entities: entities))
return TelegramMediaAction(action: .giftPremium(currency: currency, amount: amount, days: days, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, text: text, entities: entities))
case let .messageActionGiftStars(_, currency, amount, stars, cryptoCurrency, cryptoAmount, transactionId):
return TelegramMediaAction(action: .giftStars(currency: currency, amount: amount, count: stars, cryptoCurrency: cryptoCurrency, cryptoAmount: cryptoAmount, transactionId: transactionId))
case let .messageActionTopicCreate(_, title, iconColor, iconEmojiId):

View file

@ -1900,6 +1900,12 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
updatedState.updateStarsReactionsDefaultPrivacy(privacy: mappedPrivacy)
case let .updateMonoForumNoPaidException(flags, channelId, savedPeerId):
updatedState.updateMonoForumNoPaidException(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: savedPeerId.peerId.toInt64(), isFree: (flags & (1 << 0)) != 0)
case let .updateStarGiftAuctionState(giftId, state):
if let state = GiftAuctionContext.State.AuctionState(apiAuctionState: state) {
updatedState.updateStarGiftAuctionState(giftId: giftId, state: state)
}
case let .updateStarGiftAuctionUserState(giftId, userState):
updatedState.updateStarGiftAuctionMyState(giftId: giftId, state: GiftAuctionContext.State.MyState(apiAuctionUserState: userState))
default:
break
}
@ -3623,7 +3629,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddQuickReplyMessages: OptimizeAddMessagesState?
for operation in operations {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateGroupCallMessage, .UpdateGroupCallOpaqueMessage, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .AddPeerLiveTypingDraftUpdate, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateGroupCallChainBlocks, .UpdateGroupCallMessage, .UpdateGroupCallOpaqueMessage, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsDefaultPrivacy, .ReportMessageDelivery, .UpdateMonoForumNoPaidException, .UpdateStarGiftAuctionState, .UpdateStarGiftAuctionMyState:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -3764,6 +3770,8 @@ func replayFinalState(
var updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:]
var updatedStarsReactionsDefaultPrivacy: TelegramPaidReactionPrivacy?
var reportMessageDelivery = Set<MessageId>()
var updatedStarGiftAuctionState: [Int64: GiftAuctionContext.State.AuctionState] = [:]
var updatedStarGiftAuctionMyState: [Int64: GiftAuctionContext.State.MyState] = [:]
var holesFromPreviousStateMessageIds: [MessageId] = []
var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:]
@ -4906,7 +4914,7 @@ func replayFinalState(
}
switch call {
case let .groupCall(flags, _, _, participantsCount, title, _, recordStartDate, scheduleDate, _, _, _, _, sendPaidMessagesStars):
case let .groupCall(flags, _, _, participantsCount, title, _, recordStartDate, scheduleDate, _, _, _, _, sendPaidMessagesStars, _):
let isMin = (flags & (1 << 19)) != 0
let isMuted = (flags & (1 << 1)) != 0
let canChange = (flags & (1 << 2)) != 0
@ -5322,6 +5330,10 @@ func replayFinalState(
transaction.setMessageHistoryThreadInfo(peerId: peerId, threadId: threadId, info: entry)
}
}
case let .UpdateStarGiftAuctionState(giftId, state):
updatedStarGiftAuctionState[giftId] = state
case let .UpdateStarGiftAuctionMyState(giftId, state):
updatedStarGiftAuctionMyState[giftId] = state
}
}
@ -5870,6 +5882,8 @@ func replayFinalState(
updatedStarsRevenueStatus: updatedStarsRevenueStatus,
sentScheduledMessageIds: finalState.state.sentScheduledMessageIds,
reportMessageDelivery: reportMessageDelivery,
addedConferenceInvitationMessagesIds: addedConferenceInvitationMessagesIds
addedConferenceInvitationMessagesIds: addedConferenceInvitationMessagesIds,
updatedStarGiftAuctionState: updatedStarGiftAuctionState,
updatedStarGiftAuctionMyState: updatedStarGiftAuctionMyState
)
}

View file

@ -52,6 +52,14 @@ private final class UpdatedStarsRevenueStatusSubscriberContext {
let subscribers = Bag<([PeerId: StarsRevenueStats.Balances]) -> Void>()
}
private final class UpdatedStarGiftAuctionStateSubscriberContext {
let subscribers = Bag<([Int64: GiftAuctionContext.State.AuctionState]) -> Void>()
}
private final class UpdatedStarGiftAuctionMyStateSubscriberContext {
let subscribers = Bag<([Int64: GiftAuctionContext.State.MyState]) -> Void>()
}
public enum DeletedMessageId: Hashable {
case global(Int32)
case messageId(MessageId)
@ -357,6 +365,8 @@ public final class AccountStateManager {
private var updatedStarsBalanceContext = UpdatedStarsBalanceSubscriberContext()
private var updatedTonBalanceContext = UpdatedStarsBalanceSubscriberContext()
private var updatedStarsRevenueStatusContext = UpdatedStarsRevenueStatusSubscriberContext()
private var updatedStarGiftAuctionStateContext = UpdatedStarGiftAuctionStateSubscriberContext()
private var updatedStarGiftAuctionMyStateContext = UpdatedStarGiftAuctionMyStateSubscriberContext()
private let delayNotificatonsUntil = Atomic<Int32?>(value: nil)
private let appliedMaxMessageIdPromise = Promise<Int32?>(nil)
@ -1121,6 +1131,12 @@ public final class AccountStateManager {
if !events.updatedStarsRevenueStatus.isEmpty {
strongSelf.notifyUpdatedStarsRevenueStatus(events.updatedStarsRevenueStatus)
}
if !events.updatedStarGiftAuctionState.isEmpty {
strongSelf.notifyUpdatedStarGiftAuctionState(events.updatedStarGiftAuctionState)
}
if !events.updatedStarGiftAuctionMyState.isEmpty {
strongSelf.notifyUpdatedStarGiftAuctionMyState(events.updatedStarGiftAuctionMyState)
}
if !events.updatedCalls.isEmpty {
for call in events.updatedCalls {
strongSelf.callSessionManager?.updateSession(call, completion: { _ in })
@ -1788,6 +1804,60 @@ public final class AccountStateManager {
subscriber(updatedStarsRevenueStatus)
}
}
public func updatedStarGiftAuctionState() -> Signal<[Int64: GiftAuctionContext.State.AuctionState], NoError> {
let queue = self.queue
return Signal { [weak self] subscriber in
let disposable = MetaDisposable()
queue.async {
if let strongSelf = self {
let index = strongSelf.updatedStarGiftAuctionStateContext.subscribers.add({ starsBalance in
subscriber.putNext(starsBalance)
})
disposable.set(ActionDisposable {
if let strongSelf = self {
strongSelf.updatedStarGiftAuctionStateContext.subscribers.remove(index)
}
})
}
}
return disposable
}
}
private func notifyUpdatedStarGiftAuctionState(_ updatedStarGiftAuctionState: [Int64: GiftAuctionContext.State.AuctionState]) {
for subscriber in self.updatedStarGiftAuctionStateContext.subscribers.copyItems() {
subscriber(updatedStarGiftAuctionState)
}
}
public func updatedStarGiftAuctionMyState() -> Signal<[Int64: GiftAuctionContext.State.MyState], NoError> {
let queue = self.queue
return Signal { [weak self] subscriber in
let disposable = MetaDisposable()
queue.async {
if let strongSelf = self {
let index = strongSelf.updatedStarGiftAuctionMyStateContext.subscribers.add({ starsBalance in
subscriber.putNext(starsBalance)
})
disposable.set(ActionDisposable {
if let strongSelf = self {
strongSelf.updatedStarGiftAuctionMyStateContext.subscribers.remove(index)
}
})
}
}
return disposable
}
}
private func notifyUpdatedStarGiftAuctionMyState(_ updatedStarGiftAuctionMyState: [Int64: GiftAuctionContext.State.MyState]) {
for subscriber in self.updatedStarGiftAuctionMyStateContext.subscribers.copyItems() {
subscriber(updatedStarGiftAuctionMyState)
}
}
func notifyDeletedMessages(messageIds: [MessageId]) {
self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) })
@ -2162,6 +2232,19 @@ public final class AccountStateManager {
}
}
public func updatedStarGiftAuctionState() -> Signal<[Int64: GiftAuctionContext.State.AuctionState], NoError> {
return self.impl.signalWith { impl, subscriber in
return impl.updatedStarGiftAuctionState().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
}
}
public func updatedStarGiftAuctionMyState() -> Signal<[Int64: GiftAuctionContext.State.MyState], NoError> {
return self.impl.signalWith { impl, subscriber in
return impl.updatedStarGiftAuctionMyState().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
}
}
func addCustomOperation<T, E>(_ f: Signal<T, E>) -> Signal<T, E> {
return self.impl.signalWith { impl, subscriber in
return impl.addCustomOperation(f).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)

View file

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 217
return 218
}
public func parseMessage(_ data: Data!) -> Any! {

View file

@ -227,7 +227,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case setChatTheme(chatTheme: ChatTheme)
case joinedByRequest
case webViewData(String)
case giftPremium(currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, text: String?, entities: [MessageTextEntity]?)
case giftPremium(currency: String, amount: Int64, days: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, text: String?, entities: [MessageTextEntity]?)
case topicCreated(title: String, iconColor: Int32, iconFileId: Int64?)
case topicEdited(components: [ForumTopicEditComponent])
case suggestedProfilePhoto(image: TelegramMediaImage?)
@ -330,7 +330,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case 26:
self = .webViewData(decoder.decodeStringForKey("t", orElse: ""))
case 27:
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), months: decoder.decodeInt32ForKey("months", orElse: 0), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"))
self = .giftPremium(currency: decoder.decodeStringForKey("currency", orElse: ""), amount: decoder.decodeInt64ForKey("amount", orElse: 0), days: decoder.decodeInt32ForKey("days", orElse: decoder.decodeInt32ForKey("months", orElse: 0) * 30), cryptoCurrency: decoder.decodeOptionalStringForKey("cryptoCurrency"), cryptoAmount: decoder.decodeOptionalInt64ForKey("cryptoAmount"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"))
case 28:
self = .topicCreated(title: decoder.decodeStringForKey("title", orElse: ""), iconColor: decoder.decodeInt32ForKey("iconColor", orElse: 0), iconFileId: decoder.decodeOptionalInt64ForKey("iconFileId"))
case 29:
@ -553,11 +553,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case let .webViewData(text):
encoder.encodeInt32(26, forKey: "_rawValue")
encoder.encodeString(text, forKey: "t")
case let .giftPremium(currency, amount, months, cryptoCurrency, cryptoAmount, text, entities):
case let .giftPremium(currency, amount, days, cryptoCurrency, cryptoAmount, text, entities):
encoder.encodeInt32(27, forKey: "_rawValue")
encoder.encodeString(currency, forKey: "currency")
encoder.encodeInt64(amount, forKey: "amount")
encoder.encodeInt32(months, forKey: "months")
encoder.encodeInt32(days, forKey: "days")
if let cryptoCurrency = cryptoCurrency, let cryptoAmount = cryptoAmount {
encoder.encodeString(cryptoCurrency, forKey: "cryptoCurrency")
encoder.encodeInt64(cryptoAmount, forKey: "cryptoAmount")

View file

@ -143,7 +143,7 @@ public struct GroupCallSummary: Equatable {
extension GroupCallInfo {
init?(_ call: Api.GroupCall) {
switch call {
case let .groupCall(flags, id, accessHash, participantsCount, title, streamDcId, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars):
case let .groupCall(flags, id, accessHash, participantsCount, title, streamDcId, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars, _):
self.init(
id: id,
accessHash: accessHash,
@ -773,7 +773,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
maybeParsedCall = GroupCallInfo(call)
switch call {
case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars):
case let .groupCall(flags, _, _, _, title, _, recordStartDate, scheduleDate, _, unmutedVideoLimit, _, _, sendPaidMessagesStars, _):
let isMin = (flags & (1 << 19)) != 0
let isMuted = (flags & (1 << 1)) != 0
let canChange = (flags & (1 << 2)) != 0
@ -4277,7 +4277,8 @@ public final class GroupCallMessagesContext {
text: text,
entities: apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary())
),
allowPaidStars: paidStars
allowPaidStars: paidStars,
sendAs: nil
)) |> deliverOn(self.queue)).startStrict(next: { [weak self] updates in
guard let self else {
return
@ -4330,7 +4331,8 @@ public final class GroupCallMessagesContext {
text: "",
entities: []
),
allowPaidStars: pendingSendStars.amount
allowPaidStars: pendingSendStars.amount,
sendAs: nil
)) |> deliverOn(self.queue)).startStrict(next: { [weak self] updates in
guard let self else {
return

View file

@ -1112,11 +1112,12 @@ func _internal_cancelStoryUpload(account: Account, stableId: Int32) {
}).start()
}
func _internal_beginStoryLivestream(account: Account, peerId: EnginePeer.Id, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool) -> Signal<EngineStoryItem?, NoError> {
func _internal_beginStoryLivestream(account: Account, peerId: EnginePeer.Id, rtmp: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, messagesEnabled: Bool, sendPaidMessageStars: Int64?) -> Signal<EngineStoryItem?, NoError> {
return account.postbox.transaction { transaction in
var flags: Int32 = 0
//flags |= 1 << 5
if rtmp {
flags |= 1 << 5
}
if isForwardingDisabled {
flags |= 1 << 4
}
@ -1128,7 +1129,14 @@ func _internal_beginStoryLivestream(account: Account, peerId: EnginePeer.Id, pri
inputPeer = .inputPeerSelf
}
return account.network.request(Api.functions.stories.startLive(flags: flags, peer: inputPeer, caption: nil, entities: nil, privacyRules: [.inputPrivacyValueAllowAll], randomId: Int64.random(in: Int64.min ... Int64.max), messagesEnabled: nil, sendPaidMessagesStars: nil))
flags |= 1 << 6
if let sendPaidMessageStars, sendPaidMessageStars > 0 {
flags |= 1 << 7
}
let privacyRules = apiInputPrivacyRules(privacy: privacy, transaction: transaction)
return account.network.request(Api.functions.stories.startLive(flags: flags, peer: inputPeer, caption: nil, entities: nil, privacyRules: privacyRules, randomId: Int64.random(in: Int64.min ... Int64.max), messagesEnabled: messagesEnabled ? .boolTrue : .boolFalse, sendPaidMessagesStars: sendPaidMessageStars))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
@ -1138,7 +1146,7 @@ func _internal_beginStoryLivestream(account: Account, peerId: EnginePeer.Id, pri
account.stateManager.addUpdates(updates)
for update in updates.allUpdates {
if case let .updateStory(_, apiStory) = update {
if case let .updateStory(_, apiStory) = update, case .storyItem = apiStory {
return account.postbox.transaction { transaction in
if let storedItem = Stories.StoredItem(apiStoryItem: apiStory, peerId: peerId, transaction: transaction), case let .item(item) = storedItem, let media = item.media {
let mappedItem = EngineStoryItem(

View file

@ -1414,8 +1414,8 @@ public extension TelegramEngine {
return _internal_uploadStory(account: self.account, target: target, media: media, mediaAreas: mediaAreas, text: text, entities: entities, pin: pin, privacy: privacy, isForwardingDisabled: isForwardingDisabled, period: period, randomId: randomId, forwardInfo: forwardInfo, folders: folders, uploadInfo: uploadInfo)
}
public func beginStoryLivestream(peerId: EnginePeer.Id, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool) -> Signal<EngineStoryItem?, NoError> {
return _internal_beginStoryLivestream(account: self.account, peerId: peerId, privacy: privacy, isForwardingDisabled: isForwardingDisabled)
public func beginStoryLivestream(peerId: EnginePeer.Id, rtmp: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, messagesEnabled: Bool, sendPaidMessageStars: Int64?) -> Signal<EngineStoryItem?, NoError> {
return _internal_beginStoryLivestream(account: self.account, peerId: peerId, rtmp: rtmp, privacy: privacy, isForwardingDisabled: isForwardingDisabled, messagesEnabled: messagesEnabled, sendPaidMessageStars: sendPaidMessageStars)
}
public func allStoriesUploadEvents() -> Signal<(Int32, Int32), NoError> {

View file

@ -20,6 +20,7 @@ public enum BotPaymentInvoiceSource {
case starGiftResale(slug: String, toPeerId: EnginePeer.Id, ton: Bool)
case starGiftPrepaidUpgrade(peerId: EnginePeer.Id, hash: String)
case starGiftDropOriginalDetails(reference: StarGiftReference)
case starGiftAuctionBid(hideName: Bool, updateBid: Bool, peerId: EnginePeer.Id, giftId: Int64, bidAmount: Int64, text: String?, entities: [MessageTextEntity]?)
}
public struct BotPaymentInvoiceFields: OptionSet {
@ -423,6 +424,24 @@ func _internal_parseInputInvoice(transaction: Transaction, source: BotPaymentInv
return .inputInvoiceStarGiftPrepaidUpgrade(peer: inputPeer, hash: hash)
case let .starGiftDropOriginalDetails(reference):
return reference.apiStarGiftReference(transaction: transaction).flatMap { .inputInvoiceStarGiftDropOriginalDetails(stargift: $0) }
case let .starGiftAuctionBid(hideName, updateBid, peerId, giftId, bidAmount, text, entities):
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
return nil
}
var flags: Int32 = 0
if hideName {
flags |= (1 << 0)
}
if updateBid {
flags |= (1 << 2)
}
var message: Api.TextWithEntities?
if let text, !text.isEmpty {
flags |= (1 << 1)
message = .textWithEntities(text: text, entities: entities.flatMap { apiEntitiesFromMessageTextEntities($0, associatedPeers: SimpleDictionary()) } ?? [])
}
return .inputInvoiceStarGiftAuctionBid(flags: flags, peer: inputPeer, giftId: giftId, bidAmount: bidAmount, message: message)
}
}
@ -765,7 +784,7 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa
receiptMessageId = id
}
}
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails:
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid:
receiptMessageId = nil
}
}

View file

@ -44,6 +44,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
public static let isBirthdayGift = Flags(rawValue: 1 << 0)
public static let requiresPremium = Flags(rawValue: 1 << 1)
public static let peerColorAvailable = Flags(rawValue: 1 << 2)
public static let isAuction = Flags(rawValue: 1 << 3)
}
enum CodingKeys: String, CodingKey {
@ -970,6 +971,9 @@ extension StarGift {
if (apiFlags & (1 << 10)) != 0 {
flags.insert(.peerColorAvailable)
}
if (apiFlags & (1 << 11)) != 0 {
flags.insert(.isAuction)
}
var availability: StarGift.Gift.Availability?
if let availabilityRemains, let availabilityTotal {

View file

@ -0,0 +1,207 @@
import Foundation
import Postbox
import MtProtoKit
import SwiftSignalKit
import TelegramApi
private func _internal_getStarGiftAuctionState(postbox: Postbox, network: Network, accountPeerId: EnginePeer.Id, giftId: Int64, version: Int32) -> Signal<(state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> {
return network.request(Api.functions.payments.getStarGiftAuctionState(giftId: giftId, version: version))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.payments.StarGiftAuctionState?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<(state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> in
guard let result else {
return .single(nil)
}
return postbox.transaction { transaction -> (state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)? in
switch result {
case let .starGiftAuctionState(state, userState, timeout, users):
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
return (
state: GiftAuctionContext.State.AuctionState(apiAuctionState: state),
myState: GiftAuctionContext.State.MyState(apiAuctionUserState: userState),
timeout: timeout
)
}
}
}
}
public final class GiftAuctionContext {
public struct State: Equatable {
public struct BidLevel: Equatable {
public var position: Int32
public var amount: Int64
public var date: Int32
}
public enum AuctionState: Equatable {
case ongoing(version: Int32, minBidAmount: Int64, bidLevels: [BidLevel], topBidders: [EnginePeer.Id], dropSize: Int32, nextDropDate: Int32, dropsLeft: Int32, dropsTotal: Int32)
case finished
}
public struct MyState: Equatable {
public var bidAmount: Int64?
public var bidDate: Int32?
public var minBidAmount: Int64?
public var acquiredCount: Int32
}
public var auctionState: AuctionState
public var myState: MyState
}
private let queue: Queue = .mainQueue()
private let account: Account
private let giftId: Int64
private let disposable = MetaDisposable()
private var auctionState: State.AuctionState?
private var myState: State.MyState?
private var timeout: Int32?
private var updateAuctionStateDisposable: Disposable?
private var updateMyStateDisposable: Disposable?
private var updateTimer: SwiftSignalKit.Timer?
private let stateValue = Promise<State?>()
public var state: Signal<State?, NoError> {
return self.stateValue.get()
}
public init(account: Account, giftId: Int64) {
self.account = account
self.giftId = giftId
self.load()
self.updateAuctionStateDisposable = (self.account.stateManager.updatedStarGiftAuctionState()
|> mapToSignal { updates in
if let update = updates[giftId] {
return .single(update)
}
return .complete()
}
|> deliverOnMainQueue).start(next: { [weak self] auctionState in
guard let self else {
return
}
if case let .ongoing(version, _, _, _, _, _, _, _) = auctionState, version < self.currentVersion {
} else {
self.auctionState = auctionState
}
self.pushState()
})
self.updateMyStateDisposable = (self.account.stateManager.updatedStarGiftAuctionMyState()
|> mapToSignal { updates in
if let update = updates[giftId] {
return .single(update)
}
return .complete()
}
|> deliverOnMainQueue).start(next: { [weak self] myState in
guard let self else {
return
}
self.myState = myState
self.pushState()
})
}
deinit {
self.updateAuctionStateDisposable?.dispose()
self.updateMyStateDisposable?.dispose()
self.updateTimer?.invalidate()
self.disposable.dispose()
}
private var currentVersion: Int32 {
var currentVersion: Int32 = 0
if case let .ongoing(version, _, _, _, _, _, _, _) = self.auctionState {
currentVersion = version
}
return currentVersion
}
public func load() {
self.pushState()
self.disposable.set((_internal_getStarGiftAuctionState(postbox: self.account.postbox, network: self.account.network, accountPeerId: self.account.peerId, giftId: self.giftId, version: self.currentVersion)
|> deliverOn(self.queue)).start(next: { [weak self] data in
guard let self else {
return
}
guard let (auctionState, myState, timeout) = data else {
return
}
if case let .ongoing(version, _, _, _, _, _, _, _) = auctionState, version < self.currentVersion {
} else if let auctionState {
self.auctionState = auctionState
}
self.myState = myState
self.timeout = timeout
self.pushState()
self.updateTimer?.invalidate()
self.updateTimer = SwiftSignalKit.Timer(timeout: Double(timeout), repeat: false, completion: { [weak self] _ in
guard let self else {
return
}
self.load()
}, queue: Queue.mainQueue())
self.updateTimer?.start()
}))
}
private func pushState() {
if let auctionState = self.auctionState, let myState = self.myState {
self.stateValue.set(.single(
State(auctionState: auctionState, myState: myState)
))
} else {
self.stateValue.set(.single(nil))
}
}
}
extension GiftAuctionContext.State.BidLevel {
init(apiBidLevel: Api.AuctionBidLevel) {
switch apiBidLevel {
case let .auctionBidLevel(pos, amount, date):
self.position = pos
self.amount = amount
self.date = date
}
}
}
extension GiftAuctionContext.State.AuctionState {
init?(apiAuctionState: Api.StarGiftAuctionState) {
switch apiAuctionState {
case let .starGiftAuctionState(version, minBidAmount, bidLevels, topBidders, dropSize, nextDropAt, dropsLeft, dropsTotal):
self = .ongoing(version: version, minBidAmount: minBidAmount, bidLevels: bidLevels.map(GiftAuctionContext.State.BidLevel.init(apiBidLevel:)), topBidders: topBidders.map { EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }, dropSize: dropSize, nextDropDate: nextDropAt, dropsLeft: dropsLeft, dropsTotal: dropsTotal)
case .starGiftAuctionStateFinished:
self = .finished
case .starGiftAuctionStateNotModified:
return nil
}
}
}
extension GiftAuctionContext.State.MyState {
init(apiAuctionUserState: Api.StarGiftAuctionUserState) {
switch apiAuctionUserState {
case let .starGiftAuctionUserState(_, bidAmount, bidDate, minBidAmount, acquiredCount):
self.bidAmount = bidAmount
self.bidDate = bidDate
self.minBidAmount = minBidAmount
self.acquiredCount = acquiredCount
}
}
}

View file

@ -1630,7 +1630,7 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
receiptMessageId = id
}
}
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails:
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid:
receiptMessageId = nil
}
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, peerId, _, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars, _) = action.action, case let .Id(messageId) = message.id {

View file

@ -27,7 +27,7 @@ public final class AnimatedTextComponent: Component {
public enum Content: Equatable {
case text(String)
case number(Int, minDigits: Int)
case icon(String, offset: CGPoint)
case icon(String, tint: Bool, offset: CGPoint)
}
public var id: AnyHashable
@ -149,7 +149,7 @@ public final class AnimatedTextComponent: Component {
} else {
itemText = valueText.map(String.init)
}
case let .icon(iconName, _):
case let .icon(iconName, _, _):
let characterKey = CharacterKey(itemId: item.id, index: 0, value: iconName)
validKeys.append(characterKey)
}
@ -188,11 +188,11 @@ public final class AnimatedTextComponent: Component {
for item in component.items {
enum AnimatedTextCharacter {
case text(String)
case icon(String, CGPoint)
case icon(String, Bool, CGPoint)
var value: String {
switch self {
case let .text(value), let .icon(value, _):
case let .text(value), let .icon(value, _, _):
return value
}
}
@ -216,8 +216,8 @@ public final class AnimatedTextComponent: Component {
} else {
itemText = valueText.map { .text(String($0)) }
}
case let .icon(iconName, offset):
itemText = [.icon(iconName, offset)]
case let .icon(iconName, tint, offset):
itemText = [.icon(iconName, tint, offset)]
}
var index = 0
for character in itemText {
@ -243,10 +243,10 @@ public final class AnimatedTextComponent: Component {
font: component.font,
color: component.color
))
case let .icon(iconName, offset):
case let .icon(iconName, tint, offset):
characterComponent = AnyComponent(BundleIconComponent(
name: iconName,
tintColor: component.color
tintColor: tint ? component.color : nil
))
characterOffset = offset
}

View file

@ -143,8 +143,8 @@ private final class AttachmentFileSearchItemNode: ItemListControllerSearchNode {
theme: self.theme,
strings: self.strings,
metrics: layout.metrics,
safeInsets: layout.safeInsets,
placeholder: self.strings.Attachment_FilesSearchPlaceholder,
resetText: nil,
updated: { [weak self] query in
guard let self else {
return
@ -161,11 +161,11 @@ private final class AttachmentFileSearchItemNode: ItemListControllerSearchNode {
)
),
environment: {},
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: layout.size.height)
containerSize: CGSize(width: layout.size.width, height: layout.size.height)
)
let bottomInset: CGFloat = layout.insets(options: .input).bottom
let searchInputFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
let searchInputFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - bottomInset - searchInputSize.height), size: searchInputSize)
if let searchInputView = self.searchInput.view as? SearchInputPanelComponent.View {
if searchInputView.superview == nil {
self.view.addSubview(searchInputView)

View file

@ -536,7 +536,7 @@ public final class ButtonComponent: Component {
transition: contentItemTransition,
component: component.content.component,
environment: {},
containerSize: CGSize(width: availableSize.width - cornerRadius * 2.0, height: availableSize.height)
containerSize: CGSize(width: availableSize.width - cornerRadius, height: availableSize.height)
)
if let contentView = contentItem.view.view {
var animateIn = false

View file

@ -90,6 +90,7 @@ swift_library(
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/ShareWithPeersScreen",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/TelegramCallsUI",
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",

View file

@ -10,6 +10,8 @@ import TelegramCallsUI
import TelegramPresentationData
import StoryContainerScreen
import ChatEntityKeyboardInputNode
import AvatarNode
import MultilineTextComponent
final class CameraLiveStreamComponent: Component {
let context: AccountContext
@ -19,6 +21,7 @@ final class CameraLiveStreamComponent: Component {
let story: EngineStoryItem?
let statusBarHeight: CGFloat
let inputHeight: CGFloat
let safeInsets: UIEdgeInsets
let metrics: LayoutMetrics
let deviceMetrics: DeviceMetrics
let didSetupMediaStream: (PresentationGroupCall) -> Void
@ -31,6 +34,7 @@ final class CameraLiveStreamComponent: Component {
story: EngineStoryItem?,
statusBarHeight: CGFloat,
inputHeight: CGFloat,
safeInsets: UIEdgeInsets,
metrics: LayoutMetrics,
deviceMetrics: DeviceMetrics,
didSetupMediaStream: @escaping (PresentationGroupCall) -> Void
@ -42,6 +46,7 @@ final class CameraLiveStreamComponent: Component {
self.story = story
self.statusBarHeight = statusBarHeight
self.inputHeight = inputHeight
self.safeInsets = safeInsets
self.metrics = metrics
self.deviceMetrics = deviceMetrics
self.didSetupMediaStream = didSetupMediaStream
@ -69,6 +74,9 @@ final class CameraLiveStreamComponent: Component {
if lhs.inputHeight != rhs.inputHeight {
return false
}
if lhs.safeInsets != rhs.safeInsets {
return false
}
if lhs.metrics != rhs.metrics {
return false
}
@ -145,7 +153,7 @@ final class CameraLiveStreamComponent: Component {
}
let itemSetContainerInsets = UIEdgeInsets(top: component.statusBarHeight + 5.0, left: 0.0, bottom: 0.0, right: 0.0)
let itemSetContainerSafeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 20.0, right: 0.0)
let itemSetContainerSafeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 34.0, right: 0.0)
let _ = liveChat.update(
transition: mediaStreamTransition,
@ -188,10 +196,6 @@ final class CameraLiveStreamComponent: Component {
// environment.controller()?.presentInGlobalOverlay(c, with: a)
},
close: {
// guard let self, let environment = self.environment else {
// return
// }
// environment.controller()?.dismiss()
},
navigate: { _ in
},
@ -253,3 +257,128 @@ final class CameraLiveStreamComponent: Component {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
public final class StreamAsComponent: Component {
let context: AccountContext
let peerId: EnginePeer.Id
public init(
context: AccountContext,
peerId: EnginePeer.Id
) {
self.context = context
self.peerId = peerId
}
public static func ==(lhs: StreamAsComponent, rhs: StreamAsComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.peerId != rhs.peerId {
return false
}
return true
}
public final class View: UIView {
private let avatarNode: AvatarNode
private let title = ComponentView<Empty>()
private let subtitle = ComponentView<Empty>()
private var arrow = UIImageView()
private var component: StreamAsComponent?
private weak var state: EmptyComponentState?
private var peer: EnginePeer?
public override init(frame: CGRect) {
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 18.0))
self.arrow.image = generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: UIColor(white: 1.0, alpha: 0.8))
super.init(frame: frame)
self.addSubnode(self.avatarNode)
self.addSubview(self.arrow)
}
public required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func update(component: StreamAsComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
if self.peer?.id != component.peerId {
let _ = (component.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: component.peerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let self, let peer else {
return
}
self.peer = peer
self.state?.updated()
})
}
self.avatarNode.frame = CGRect(origin: .zero, size: CGSize(width: 32.0, height: 32.0))
if let peer = self.peer {
self.avatarNode.setPeer(
context: component.context,
theme: component.context.sharedContext.currentPresentationData.with({ $0 }).theme,
peer: peer,
synchronousLoad: true
)
}
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: self.peer?.compactDisplayTitle ?? "", font: Font.semibold(14.0), textColor: .white, paragraphAlignment: .left))
)
),
environment: {},
containerSize: CGSize(width: availableSize.width - 38.0, height: availableSize.height)
)
let titleFrame = CGRect(origin: CGPoint(x: 42.0, y: 1.0), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
self.addSubview(titleView)
}
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)
}
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)
}
return CGSize(width: max(titleFrame.maxX, subtitleFrame.maxX + 16.0), height: 32.0)
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -29,6 +29,7 @@ import ShareWithPeersScreen
import TelegramVoip
import TelegramCallsUI
import GlassBarButtonComponent
import PlainButtonComponent
let videoRedColor = UIColor(rgb: 0xff3b30)
let collageGrids: [Camera.CollageGrid] = [
@ -298,6 +299,23 @@ private final class CameraScreenComponent: CombinedComponent {
private var volumeButtonsListener: VolumeButtonsListener?
private let volumeButtonsListenerShouldBeActive = ValuePromise<Bool>(false, ignoreRepeated: true)
private var closeFriends = Promise<[EnginePeer]>()
private var adminedChannels = Promise<[EnginePeer]>()
private var storiesBlockedPeers: BlockedPeersContext?
fileprivate var sendAsPeerId: EnginePeer.Id?
private var privacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
private var allowComments = true
private var isForwardingDisabled = false
private var pin = true
private var paidMessageStars: Int64 = 0
private(set) var liveStreamStory: EngineStoryItem?
private weak var liveStreamCall: PresentationGroupCall?
private var liveStreamVideoCapturer: OngoingCallVideoCapturer?
private var liveStreamVideoDisposable: Disposable?
private var liveStreamAudioDisposable: Disposable?
var cameraState: CameraState?
var swipeHint: CaptureControlsComponent.SwipeHint = .none
@ -352,6 +370,7 @@ private final class CameraScreenComponent: CombinedComponent {
self.lastGalleryAssetsDisposable?.dispose()
self.resultDisposable.dispose()
self.liveStreamVideoDisposable?.dispose()
self.liveStreamAudioDisposable?.dispose()
}
func setupRecentAssetSubscription() {
@ -480,6 +499,12 @@ private final class CameraScreenComponent: CombinedComponent {
return
}
if mode == .live && self.storiesBlockedPeers == nil {
self.storiesBlockedPeers = BlockedPeersContext(account: self.context.account, subject: .stories)
self.adminedChannels.set(.single([]) |> then(self.context.engine.peers.channelsForStories()))
self.closeFriends.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.CloseFriends()))
}
controller.updateCameraState({ $0.updatedMode(mode) }, transition: .spring(duration: 0.3))
var flashOn = controller.cameraState.flashMode == .on
@ -873,41 +898,283 @@ private final class CameraScreenComponent: CombinedComponent {
controller.updateCameraState({ $0.updatedRecording(.handsFree) }, transition: .spring(duration: 0.4))
}
private(set) var liveStreamStory: EngineStoryItem?
func startLiveStream() {
fileprivate func presentStreamAsPeer() {
let _ = combineLatest(
queue: Queue.mainQueue(),
self.adminedChannels.get(),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
).start(next: { [weak self] sendAsPeers, accountPeer in
guard let self, let accountPeer else {
return
}
var peers = [accountPeer]
peers.append(contentsOf: sendAsPeers)
let stateContext = ShareWithPeersScreen.StateContext(
context: self.context,
subject: .peers(peers: peers, peerId: self.sendAsPeerId),
liveStream: true,
editing: false
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
guard let self, let controller = self.getController() else {
return
}
let peersController = ShareWithPeersScreen(
context: self.context,
initialPrivacy: EngineStoryPrivacy(base: .nobody, additionallyIncludePeers: []),
stateContext: stateContext,
completion: { _, _, _, _, _, _, _ in },
editCategory: { _, _, _, _ in },
editBlockedPeers: { _, _, _, _ in },
peerCompletion: { [weak self] peerId in
guard let self else {
return
}
self.sendAsPeerId = peerId
self.updated()
}
)
controller.push(peersController)
})
})
}
fileprivate func presentLiveSettings() {
let stateContext = LiveStreamSettingsScreen.StateContext(
context: self.context,
mode: .create(
sendAsPeerId: self.sendAsPeerId,
privacy: self.privacy,
allowComments: self.allowComments,
isForwardingDisabled: self.isForwardingDisabled,
pin: self.pin,
paidMessageStars: self.paidMessageStars
),
closeFriends: self.closeFriends.get(),
adminedChannels: self.adminedChannels.get(),
blockedPeersContext: self.storiesBlockedPeers
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).startStandalone(next: { [weak self] _ in
guard let self, let controller = self.getController() else {
return
}
let settingsController = LiveStreamSettingsScreen(
context: self.context,
stateContext: stateContext,
editCategory: { [weak self] privacy, allowComments, isForwardingDisabled, pin, paidMessageStars in
guard let self else {
return
}
self.openEditCategory(privacy: privacy, blockedPeers: false, completion: { [weak self] privacy in
guard let self else {
return
}
self.privacy = privacy
self.allowComments = allowComments
self.isForwardingDisabled = isForwardingDisabled
self.pin = pin
self.paidMessageStars = paidMessageStars
self.presentLiveSettings()
})
},
editBlockedPeers: { [weak self] privacy, allowComments, isForwardingDisabled, pin, paidMessageStars in
guard let self else {
return
}
self.openEditCategory(privacy: privacy, blockedPeers: true, completion: { [weak self] privacy in
guard let self else {
return
}
self.allowComments = allowComments
self.isForwardingDisabled = isForwardingDisabled
self.pin = pin
self.paidMessageStars = paidMessageStars
self.presentLiveSettings()
})
},
completion: { [weak self] result in
guard let self else {
return
}
self.sendAsPeerId = result.sendAsPeerId
self.privacy = result.privacy
self.allowComments = result.allowComments
self.isForwardingDisabled = result.isForwardingDisabled
self.pin = result.pin
self.paidMessageStars = result.paidMessageStars
if result.startRtmpStream {
self.startLiveStream(rtmp: true)
}
}
)
controller.push(settingsController)
})
}
private func openEditCategory(privacy: EngineStoryPrivacy, blockedPeers: Bool, completion: @escaping (EngineStoryPrivacy) -> Void) {
let subject: ShareWithPeersScreen.StateContext.Subject
if blockedPeers {
subject = .chats(blocked: true)
} else if privacy.base == .nobody {
subject = .chats(blocked: false)
} else {
subject = .contacts(base: privacy.base)
}
let stateContext = ShareWithPeersScreen.StateContext(
context: self.context,
subject: subject,
editing: false,
initialPeerIds: Set(privacy.additionallyIncludePeers),
blockedPeersContext: self.storiesBlockedPeers
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
guard let self, let controller = self.getController() else {
return
}
let categoryController = ShareWithPeersScreen(
context: self.context,
initialPrivacy: privacy,
stateContext: stateContext,
completion: { [weak self] _, result, _, _, peers, _, completed in
guard let self, completed else {
return
}
if blockedPeers {
let _ = self.storiesBlockedPeers?.updatePeerIds(result.additionallyIncludePeers).start()
completion(privacy)
} else if case .closeFriends = privacy.base {
let _ = self.context.engine.privacy.updateCloseFriends(peerIds: result.additionallyIncludePeers).start()
self.closeFriends.set(.single(peers))
completion(EngineStoryPrivacy(base: .closeFriends, additionallyIncludePeers: []))
} else {
completion(result)
}
},
editCategory: { _, _, _, _ in },
editBlockedPeers: { _, _, _, _ in }
)
controller.push(categoryController)
})
}
func startLiveStream(rtmp: Bool) {
guard let controller = self.getController() else {
return
}
let _ = (self.context.engine.messages.beginStoryLivestream(peerId: self.context.account.peerId, privacy: EngineStoryPrivacy(base: .nobody, additionallyIncludePeers: []), isForwardingDisabled: false)
|> deliverOnMainQueue).start(next: { [weak self, weak controller] story in
guard let self else {
let peerId = self.sendAsPeerId ?? self.context.account.peerId
let startNewLiveStream = { [weak self, weak controller] in
guard let self, let controller else {
return
}
self.liveStreamStory = story
controller?.updateCameraState({ $0.updatedIsStreaming(true) }, transition: .spring(duration: 0.4))
self.updated(transition: .immediate)
})
if rtmp {
controller.node.pauseCameraCapture()
}
let _ = (self.context.engine.messages.beginStoryLivestream(peerId: peerId, rtmp: rtmp, privacy: self.privacy, isForwardingDisabled: self.isForwardingDisabled, messagesEnabled: self.allowComments, sendPaidMessageStars: self.paidMessageStars)
|> deliverOnMainQueue).start(next: { [weak self, weak controller] story in
guard let self else {
return
}
self.liveStreamStory = story
controller?.updateCameraState({ $0.updatedIsStreaming(true) }, transition: .spring(duration: 0.4))
self.updated(transition: .immediate)
})
}
// let _ = (self.context.engine.messages.storySubscriptions(isHidden: false)
// |> take(1)
// |> deliverOnMainQueue).start(next: { [weak self, weak controller] subscriptions in
// guard let self else {
// return
// }
// if subscriptions.accountItem?.hasLiveItems == true {
// let storyList = PeerExpiringStoryListContext(account: self.context.account, peerId: peerId)
// let _ = (storyList.state
// |> filter { !$0.isLoading }
// |> take(1)
// |> deliverOnMainQueue).start(next: { [weak self, weak controller] state in
// guard let self else {
// return
// }
// for item in state.items.reversed() {
// let _ = (self.context.engine.messages.getStory(peerId: peerId, id: item.id)
// |> deliverOnMainQueue).start(next: { [weak self, weak controller] item in
// guard let self, let item else {
// return
// }
// if case .liveStream = item.media {
// self.liveStreamStory = item
// controller?.updateCameraState({ $0.updatedIsStreaming(true) }, transition: .spring(duration: 0.4))
// self.updated(transition: .immediate)
// return
// }
// })
// }
// startNewStream()
// })
// } else {
startNewLiveStream()
// }
// })
}
func endLiveStream() {
guard let controller = self.getController() else {
return
}
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let alertController = textAlertController(
context: self.context,
forceTheme: defaultDarkColorPresentationTheme,
title: "End Live Stream",
text: "Are you sure you want to end this live stream?",
actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}),
TextAlertAction(type: .genericAction, title: "End", action: { [weak self, weak controller] in
guard let self, let controller else {
return
}
let _ = self.liveStreamCall?.leave(terminateIfPossible: true).startStandalone()
controller.dismiss(animated: true)
})
]
)
controller.present(alertController, in: .window(.root))
}
private var liveStreamVideoCapturer: OngoingCallVideoCapturer?
private var liveStreamVideoDisposable: Disposable?
func setupStreamCamera(call: PresentationGroupCall) {
guard self.liveStreamVideoCapturer == nil, let call = call as? PresentationGroupCallImpl, let controller = self.getController() else {
return
}
let cameraVideoSource = controller.node.cameraVideoSource
self.liveStreamCall = call
let liveStreamMediaSource = controller.node.liveStreamMediaSource
let videoCapturer = OngoingCallVideoCapturer(keepLandscape: false, isCustom: true)
self.liveStreamVideoCapturer = videoCapturer
self.liveStreamVideoDisposable = cameraVideoSource.addOnUpdated { [weak self, weak cameraVideoSource] in
guard let self, let cameraVideoSource, let videoCapturer = self.liveStreamVideoCapturer else {
self.liveStreamVideoDisposable = liveStreamMediaSource.addOnVideoUpdated { [weak self, weak liveStreamMediaSource] in
guard let self, let liveStreamMediaSource, let videoCapturer = self.liveStreamVideoCapturer else {
return
}
if let currentOutput = cameraVideoSource.currentOutput, let pixelBuffer = currentOutput.dataBuffer.pixelBuffer, let sampleBuffer = sampleBufferFromPixelBuffer(pixelBuffer: pixelBuffer) {
if let pixelBuffer = liveStreamMediaSource.currentVideoOutput, let sampleBuffer = sampleBufferFromPixelBuffer(pixelBuffer: pixelBuffer) {
videoCapturer.injectSampleBuffer(sampleBuffer, rotation: .up, completion: {})
}
}
self.liveStreamAudioDisposable = liveStreamMediaSource.addOnAudioUpdated { [weak self, weak liveStreamMediaSource] in
guard let self, let liveStreamMediaSource, let call = self.liveStreamCall as? PresentationGroupCallImpl else {
return
}
if let audioData = liveStreamMediaSource.currentAudioOutput {
call.addExternalAudioData(data: audioData)
}
}
Queue.mainQueue().after(1.0) {
call.requestVideo(capturer: videoCapturer, useFrontCamera: false)
}
@ -942,6 +1209,7 @@ private final class CameraScreenComponent: CombinedComponent {
let endStreamButton = Child(GlassBarButtonComponent.self)
let captureControls = Child(CaptureControlsComponent.self)
let zoomControl = Child(ZoomComponent.self)
let streamAsButton = Child(PlainButtonComponent.self)
let flashButton = Child(CameraButton.self)
let flipButton = Child(CameraButton.self)
let dualButton = Child(CameraButton.self)
@ -1135,7 +1403,7 @@ private final class CameraScreenComponent: CombinedComponent {
case .video:
state.startVideoRecording(pressing: false)
case .live:
state.startLiveStream()
state.startLiveStream(rtmp: false)
}
} else {
state.stopVideoRecording()
@ -1173,11 +1441,10 @@ private final class CameraScreenComponent: CombinedComponent {
controller.presentGallery()
}
},
settingsTapped: {
guard let controller = environment.controller() as? CameraScreenImpl else {
return
settingsTapped: { [weak state] in
if let state {
state.presentLiveSettings()
}
controller.presentLiveSettings()
},
swipeHintUpdated: { [weak state] hint in
if let state {
@ -1229,6 +1496,7 @@ private final class CameraScreenComponent: CombinedComponent {
story: state.liveStreamStory,
statusBarHeight: environment.statusBarHeight,
inputHeight: environment.inputHeight,
safeInsets: environment.safeInsets,
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
didSetupMediaStream: { [weak state] call in
@ -1247,6 +1515,30 @@ private final class CameraScreenComponent: CombinedComponent {
let topControlSideInset: CGFloat = 9.0
let topControlVerticalInset: CGFloat = 12.0
let topButtonSpacing: CGFloat = 15.0
if component.cameraState.mode == .live && !component.cameraState.isStreaming {
let streamAsButton = streamAsButton.update(
component: PlainButtonComponent(
content: AnyComponent(
StreamAsComponent(context: component.context, peerId: state.sendAsPeerId ?? component.context.account.peerId)
),
action: { [weak state] in
if let state {
state.presentStreamAsPeer()
}
},
animateAlpha: true,
animateScale: false
),
availableSize: CGSize(width: 200.0, height: 40.0),
transition: .immediate
)
context.add(streamAsButton
.position(CGPoint(x: topControlSideInset + streamAsButton.size.width / 2.0 + 7.0, y: max(environment.statusBarHeight + 5.0, environment.safeInsets.top + topControlVerticalInset) + streamAsButton.size.height / 2.0 + 4.0))
.appear(.default(scale: true))
.disappear(.default(scale: true))
)
}
if component.cameraState.isStreaming {
let endStreamButton = endStreamButton.update(
@ -1256,11 +1548,10 @@ private final class CameraScreenComponent: CombinedComponent {
isDark: true,
state: .glass,
component: AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: "End", font: Font.semibold(17.0), color: .white))),
action: { _ in
guard let controller = controller() as? CameraScreenImpl else {
return
action: { [weak state] _ in
if let state {
state.endLiveStream()
}
controller.requestDismiss(animated: true)
}
),
availableSize: CGSize(width: 40.0, height: 40.0),
@ -1921,12 +2212,25 @@ public class CameraScreenImpl: ViewController, CameraScreen {
return current
} else {
let cameraVideoSource = CameraVideoSource()
self.camera?.setVideoOutput(cameraVideoSource.cameraVideoOutput)
self.camera?.setMainVideoOutput(cameraVideoSource.cameraVideoOutput)
self._cameraVideoSource = cameraVideoSource
return cameraVideoSource
}
}
private var _livestreamMediaSource: LiveStreamMediaSource?
var liveStreamMediaSource: LiveStreamMediaSource {
if let current = self._livestreamMediaSource {
return current
} else {
let livestreamMediaSource = LiveStreamMediaSource()
self.camera?.setMainVideoOutput(livestreamMediaSource.mainVideoOutput)
self.camera?.setAdditionalVideoOutput(livestreamMediaSource.additionalVideoOutput)
self._livestreamMediaSource = livestreamMediaSource
return livestreamMediaSource
}
}
var cameraState: CameraState {
didSet {
let previousPosition = oldValue.position
@ -3967,41 +4271,6 @@ public class CameraScreenImpl: ViewController, CameraScreen {
self.requestLayout(transition: .immediate)
}
func presentLiveSettings() {
let stateContext = ShareWithPeersScreen.StateContext(
context: self.context,
subject: .stories(editing: false, count: 1)
)
let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).startStandalone(next: { [weak self] _ in
guard let self else {
return
}
let controller = ShareWithPeersScreen(
context: self.context,
initialPrivacy: EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []),
stateContext: stateContext,
completion: { sendAsPeerId, privacy, allowScreenshots, pin, _, folders, completed in
},
editCategory: { privacy, allowScreenshots, pin, folders in
},
editBlockedPeers: { privacy, allowScreenshots, pin, folders in
}
)
// controller.customModalStyleOverlayTransitionFactorUpdated = { [weak self, weak controller] transition in
// if let self, let controller {
// let transitionFactor = controller.modalStyleOverlayTransitionFactor
// self.node.updateModalTransitionFactor(transitionFactor, transition: transition)
// }
// }
// controller.dismissed = {
// self.node.mediaEditor?.play()
// }
self.push(controller)
})
}
public func presentDraftTooltip() {
self.node.presentDraftTooltip()
}

View file

@ -5,6 +5,8 @@ import Display
import SwiftSignalKit
import Camera
import MetalEngine
import MediaEditor
import TelegramCore
final class CameraVideoSource: VideoSource {
private var device: MTLDevice
@ -80,3 +82,165 @@ final class CameraVideoSource: VideoSource {
}
}
}
final class LiveStreamMediaSource {
private let pool: CVPixelBufferPool?
private(set) var mainVideoOutput: CameraVideoOutput!
private(set) var additionalVideoOutput: CameraVideoOutput!
private let composer: MediaEditorComposer
private var currentMainSampleBuffer: CMSampleBuffer?
private var currentAdditionalSampleBuffer: CMSampleBuffer?
public private(set) var currentVideoOutput: CVPixelBuffer?
private var onVideoUpdatedListeners = Bag<() -> Void>()
public private(set) var currentAudioOutput: Data?
private var onAudioUpdatedListeners = Bag<() -> Void>()
public init() {
let width: Int32 = 1080
let height: Int32 = 1920
let dimensions = CGSize(width: CGFloat(width), height: CGFloat(height))
let bufferOptions: [String: Any] = [
kCVPixelBufferPoolMinimumBufferCountKey as String: 3 as NSNumber
]
let pixelBufferOptions: [String: Any] = [
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA as NSNumber,
kCVPixelBufferWidthKey as String: UInt32(width),
kCVPixelBufferHeightKey as String: UInt32(height)
]
var pool: CVPixelBufferPool?
CVPixelBufferPoolCreate(nil, bufferOptions as CFDictionary, pixelBufferOptions as CFDictionary, &pool)
self.pool = pool
let topOffset = CGPoint(x: 267.0, y: 438.0)
let additionalVideoPosition = CGPoint(x: dimensions.width - topOffset.x, y: topOffset.y)
self.composer = MediaEditorComposer(
postbox: nil,
values: MediaEditorValues(
peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)),
originalDimensions: PixelDimensions(dimensions),
cropOffset: .zero,
cropRect: CGRect(origin: .zero, size: dimensions),
cropScale: 1.0,
cropRotation: 0.0,
cropMirroring: false,
cropOrientation: nil,
gradientColors: nil,
videoTrimRange: nil,
videoIsMuted: false,
videoIsFullHd: false,
videoIsMirrored: false,
videoVolume: nil,
additionalVideoPath: nil,
additionalVideoIsDual: true,
additionalVideoPosition: additionalVideoPosition,
additionalVideoScale: 1.625,
additionalVideoRotation: 0.0,
additionalVideoPositionChanges: [],
additionalVideoTrimRange: nil,
additionalVideoOffset: nil,
additionalVideoVolume: nil,
collage: [],
nightTheme: false,
drawing: nil,
maskDrawing: nil,
entities: [],
toolValues: [:],
audioTrack: nil,
audioTrackTrimRange: nil,
audioTrackOffset: nil,
audioTrackVolume: nil,
audioTrackSamples: nil,
collageTrackSamples: nil,
coverImageTimestamp: nil,
coverDimensions: nil,
qualityPreset: nil
),
dimensions: CGSize(width: 1080.0, height: 1920.0),
outputDimensions: CGSize(width: 1080.0, height: 1920.0),
textScale: 1.0,
videoDuration: nil,
additionalVideoDuration: nil
)
self.mainVideoOutput = CameraVideoOutput(sink: { [weak self] buffer, mirror in
guard let self else {
return
}
self.currentMainSampleBuffer = try? CMSampleBuffer(copying: buffer)
self.push(mainSampleBuffer: buffer, additionalSampleBuffer: self.currentAdditionalSampleBuffer)
})
self.additionalVideoOutput = CameraVideoOutput(sink: { [weak self] buffer, mirror in
guard let self else {
return
}
self.currentAdditionalSampleBuffer = try? CMSampleBuffer(copying: buffer)
})
}
public func addOnVideoUpdated(_ f: @escaping () -> Void) -> Disposable {
let index = self.onVideoUpdatedListeners.add(f)
return ActionDisposable { [weak self] in
DispatchQueue.main.async {
guard let self else {
return
}
self.onVideoUpdatedListeners.remove(index)
}
}
}
public func addOnAudioUpdated(_ f: @escaping () -> Void) -> Disposable {
let index = self.onAudioUpdatedListeners.add(f)
return ActionDisposable { [weak self] in
DispatchQueue.main.async {
guard let self else {
return
}
self.onAudioUpdatedListeners.remove(index)
}
}
}
private func push(mainSampleBuffer: CMSampleBuffer, additionalSampleBuffer: CMSampleBuffer?) {
let timestamp = mainSampleBuffer.presentationTimeStamp
guard let mainPixelBuffer = CMSampleBufferGetImageBuffer(mainSampleBuffer) else {
return
}
let main: MediaEditorComposer.Input = .videoBuffer(VideoPixelBuffer(pixelBuffer: mainPixelBuffer, rotation: .rotate90Degrees, timestamp: timestamp), nil, 1.0, .zero)
var additional: [MediaEditorComposer.Input?] = []
if let additionalPixelBuffer = additionalSampleBuffer.flatMap({ CMSampleBufferGetImageBuffer($0) }) {
additional.append(
.videoBuffer(VideoPixelBuffer(pixelBuffer: additionalPixelBuffer, rotation: .rotate90DegreesMirrored, timestamp: timestamp), nil, 1.0, .zero)
)
}
self.composer.process(
main: main,
additional: additional,
timestamp: timestamp,
pool: self.pool,
completion: { [weak self] pixelBuffer in
guard let self else {
return
}
Queue.mainQueue().async {
self.currentVideoOutput = pixelBuffer
for onUpdated in self.onVideoUpdatedListeners.copyItems() {
onUpdated()
}
}
}
)
}
}

View file

@ -1190,6 +1190,7 @@ final class CaptureControlsComponent: Component {
let hideControls = component.hideControls
let galleryButtonFrame: CGRect
let lockReferenceFrame: CGRect
let gallerySize: CGSize
if component.hasGallery {
let galleryCornerRadius: CGFloat
@ -1231,12 +1232,10 @@ final class CaptureControlsComponent: Component {
)
if component.isTablet {
galleryButtonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - galleryButtonSize.width) / 2.0), y: size.height - galleryButtonSize.height - 56.0), size: galleryButtonSize)
lockReferenceFrame = .zero
} else {
if "".isEmpty {
galleryButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: size.height + 21.0), size: galleryButtonSize)
} else {
galleryButtonFrame = CGRect(origin: CGPoint(x: buttonSideInset, y: floorToScreenPixels((size.height - galleryButtonSize.height) / 2.0)), size: galleryButtonSize)
}
galleryButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: size.height + 21.0), size: galleryButtonSize)
lockReferenceFrame = CGRect(origin: CGPoint(x: buttonSideInset, y: floorToScreenPixels((size.height - galleryButtonSize.height) / 2.0)), size: galleryButtonSize)
}
if let galleryButtonView = self.galleryButtonView.view as? CameraButton.View {
galleryButtonView.contentView.clipsToBounds = true
@ -1258,6 +1257,7 @@ final class CaptureControlsComponent: Component {
} else {
galleryButtonFrame = .zero
gallerySize = .zero
lockReferenceFrame = .zero
}
if !component.isTablet && component.hasAccess {
@ -1288,13 +1288,6 @@ final class CaptureControlsComponent: Component {
containerSize: availableSize
)
let flipButtonFrame = CGRect(origin: CGPoint(x: flipButtonOriginX, y: (size.height - flipButtonSize.height) / 2.0), size: flipButtonSize)
//if "".isEmpty {
// flipButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - flipButtonSize.width - 16.0, y: size.height + 21.0), size: flipButtonSize)
//}
//self.flipButtonBackgroundView.update(size: CGSize(width: 48.0, height: 48.0), cornerRadius: 24.0, isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0xffffff, alpha: 0.06)), transition: .immediate)
//self.flipButtonBackgroundView.frame = flipButtonFrame.insetBy(dx: -2.0, dy: -2.0).offsetBy(dx: 2.0, dy: 2.0)
if let flipButtonView = self.flipButtonView.view {
if flipButtonView.superview == nil {
self.addSubview(flipButtonView)
@ -1306,7 +1299,9 @@ final class CaptureControlsComponent: Component {
transition.setAlpha(view: flipButtonView, alpha: !isRecording || isTransitioning || hideControls ? 0.0 : 1.0)
}
self.bottomContainerView.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height), size: CGSize(width: availableSize.width, height: 21.0 + 64.0))
let bottomContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height), size: CGSize(width: availableSize.width, height: 21.0 + 64.0))
self.bottomContainerView.frame = bottomContainerFrame
self.bottomContainerView.update(size: bottomContainerFrame.size, isDark: true, transition: .immediate)
let bottomFlipButtonSize = self.bottomFlipButton.update(
transition: .immediate,
@ -1499,7 +1494,7 @@ final class CaptureControlsComponent: Component {
lockMaskFrame = lockMaskFrame.offsetBy(dx: 0.0, dy: -8.0)
}
} else {
lockFrame = galleryButtonFrame.insetBy(dx: (gallerySize.width - hintIconSize.width) / 2.0, dy: (gallerySize.height - hintIconSize.height) / 2.0)
lockFrame = lockReferenceFrame.insetBy(dx: (gallerySize.width - hintIconSize.width) / 2.0, dy: (gallerySize.height - hintIconSize.height) / 2.0)
lockMaskFrame = CGRect(origin: CGPoint(x: availableSize.width / 2.0 - lockFrame.midX - 9.0 + self.shutterOffsetX, y: -9.0), size: CGSize(width: 48.0, height: 48.0))
if self.panBlobState == .transientToLock {
lockMaskFrame = lockMaskFrame.offsetBy(dx: 8.0, dy: 0.0)

View file

@ -224,10 +224,12 @@ final class ModeComponent: Component {
totalSize = CGSize(width: itemFrame.minX - spacing + inset, height: buttonSize.height)
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - totalSize.width) / 2.0), y: 0.0), size: totalSize))
}
transition.setFrame(view: self.glassContainerView, frame: CGRect(origin: .zero, size: self.backgroundView.frame.size))
let containerFrame = CGRect(origin: .zero, size: self.backgroundView.frame.size)
transition.setFrame(view: self.glassContainerView, frame: containerFrame)
let selectionFrame = selectedFrame.insetBy(dx: -20.0, dy: 3.0)
self.glassContainerView.alpha = 0.5
self.glassContainerView.update(size: containerFrame.size, isDark: true, transition: .immediate)
self.selectionView.update(size: selectionFrame.size, cornerRadius: selectionFrame.height * 0.5, isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0xffffff, alpha: 0.16)), transition: transition)
transition.setFrame(view: self.selectionView, frame: selectionFrame)

View file

@ -452,8 +452,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
for media in item.message.media {
if let action = media as? TelegramMediaAction {
switch action.action {
case let .giftPremium(_, _, monthsValue, _, _, giftText, giftEntities):
months = monthsValue
case let .giftPremium(_, _, daysValue, _, _, giftText, giftEntities):
months = max(3, Int32(round(Float(daysValue) / 30.0)))
if months == 12 {
title = item.presentationData.strings.Notification_PremiumGift_YearsTitle(1)
} else {

View file

@ -228,7 +228,7 @@ final class ComposeTodoScreenComponent: Component {
let theme = environment.theme.withModalBlocksBackground()
let backgroundView = UIImageView(image: generateReorderingBackgroundImage(backgroundColor: theme.list.itemBlocksBackgroundColor))
backgroundView.frame = wrapperView.bounds.insetBy(dx: -10.0, dy: -10.0)
backgroundView.frame = wrapperView.bounds.insetBy(dx: -16.0, dy: -16.0)
snapshotView.frame = snapshotView.bounds
wrapperView.addSubview(backgroundView)

View file

@ -42,16 +42,13 @@ final class NewContactScreenComponent: Component {
let context: AccountContext
let initialData: NewContactScreen.InitialData
let completion: (TelegramMediaTodo) -> Void
init(
context: AccountContext,
initialData: NewContactScreen.InitialData,
completion: @escaping (TelegramMediaTodo) -> Void
initialData: NewContactScreen.InitialData
) {
self.context = context
self.initialData = initialData
self.completion = completion
}
static func ==(lhs: NewContactScreenComponent, rhs: NewContactScreenComponent) -> Bool {
@ -94,6 +91,8 @@ final class NewContactScreenComponent: Component {
private let phoneTag = NSObject()
private let noteTag = NSObject()
private var updateFocusTag: Any?
private var syncContactToPhone = true
private var cachedChevronImage: (UIImage, PresentationTheme)?
@ -251,21 +250,30 @@ final class NewContactScreenComponent: Component {
let theme = environment.theme
var initialCountryCode: Int32?
var initialFocusTag: Any?
var updateFocusTag: Any?
if self.component == nil {
if let peer = component.initialData.peer {
self.resolvedPeer = .peer(peer: peer, isContact: false)
}
let countryCode: Int32
if let phone = component.initialData.phoneNumber {
if let (_, code) = lookupCountryIdByNumber(phone, configuration: component.context.currentCountriesConfiguration.with { $0 }), let codeValue = Int32(code.code) {
countryCode = codeValue
} else if phone.hasPrefix("999") {
countryCode = 93
} else {
countryCode = AuthorizationSequenceCountrySelectionController.defaultCountryCode()
}
initialFocusTag = self.firstNameTag
updateFocusTag = self.firstNameTag
} else {
countryCode = AuthorizationSequenceCountrySelectionController.defaultCountryCode()
initialFocusTag = self.phoneTag
updateFocusTag = self.phoneTag
}
initialCountryCode = countryCode
} else {
updateFocusTag = self.updateFocusTag
self.updateFocusTag = nil
}
self.component = component
@ -304,8 +312,15 @@ final class NewContactScreenComponent: Component {
placeholder: "First Name",
autocapitalizationType: .sentences,
autocorrectionType: .default,
returnKeyType: .next,
updated: { value in
},
onReturn: { [weak self] in
guard let self else {
return
}
self.updateFocusTag = self.lastNameTag
self.state?.updated()
},
tag: self.firstNameTag
))),
@ -317,8 +332,15 @@ final class NewContactScreenComponent: Component {
placeholder: "Last Name",
autocapitalizationType: .sentences,
autocorrectionType: .default,
returnKeyType: .next,
updated: { value in
},
onReturn: { [weak self] in
guard let self else {
return
}
self.updateFocusTag = self.phoneTag
self.state?.updated()
},
tag: self.lastNameTag
)))
@ -483,11 +505,15 @@ final class NewContactScreenComponent: Component {
}
},
tapAction: { [weak self] _, _ in
guard let self else {
guard let self, let component = self.component else {
return
}
if case let .peer(peer, _) = self.resolvedPeer {
let _ = peer
if let infoController = component.context.sharedContext.makePeerInfoController(context: component.context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
if let navigationController = component.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(infoController)
}
}
} else {
self.sendInvite()
}
@ -825,8 +851,8 @@ final class NewContactScreenComponent: Component {
transition.setFrame(view: doneButtonView, frame: doneButtonFrame)
}
if let initialFocusTag {
self.activateInput(tag: initialFocusTag)
if let updateFocusTag {
self.activateInput(tag: updateFocusTag)
}
return availableSize
@ -844,15 +870,18 @@ final class NewContactScreenComponent: Component {
public class NewContactScreen: ViewControllerComponentContainer {
public final class InitialData {
fileprivate let peer: EnginePeer?
fileprivate let firstName: String?
fileprivate let lastName: String?
fileprivate let phoneNumber: String?
fileprivate init(
peer: EnginePeer?,
firstName: String?,
lastName: String?,
phoneNumber: String?
) {
self.peer = peer
self.firstName = firstName
self.lastName = lastName
self.phoneNumber = phoneNumber
@ -860,13 +889,13 @@ public class NewContactScreen: ViewControllerComponentContainer {
}
private let context: AccountContext
fileprivate let completion: (TelegramMediaTodo) -> Void
fileprivate let completion: (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void
private var isDismissed: Bool = false
public init(
context: AccountContext,
initialData: InitialData,
completion: @escaping (TelegramMediaTodo) -> Void
completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void
) {
self.context = context
self.completion = completion
@ -876,8 +905,7 @@ public class NewContactScreen: ViewControllerComponentContainer {
super.init(context: context, component: NewContactScreenComponent(
context: context,
initialData: initialData,
completion: completion
initialData: initialData
), navigationBarAppearance: .none, theme: .default)
self._hasGlassStyle = true
@ -899,15 +927,24 @@ public class NewContactScreen: ViewControllerComponentContainer {
}
public static func initialData(
firstName: String? = nil,
lastName: String? = nil,
peer: EnginePeer? = nil,
phoneNumber: String? = nil
) -> InitialData {
return InitialData(
firstName: firstName,
lastName: lastName,
phoneNumber: phoneNumber
)
if case let .user(user) = peer {
return InitialData(
peer: peer,
firstName: user.firstName,
lastName: user.lastName,
phoneNumber: user.phone ?? phoneNumber
)
} else {
return InitialData(
peer: nil,
firstName: nil,
lastName: nil,
phoneNumber: phoneNumber
)
}
}
fileprivate func complete(result: NewContactScreenComponent.Result) {
@ -921,7 +958,11 @@ public class NewContactScreen: ViewControllerComponentContainer {
noteText: result.note.string,
noteEntities: entities,
addToPrivacyExceptions: false
).startStandalone()
).startStandalone(completed: { [weak self] in
if !result.syncContactToPhone {
self?.completion(result.peer, nil, nil)
}
})
} else {
let _ = self.context.engine.contacts.importContact(
firstName: result.firstName,
@ -931,5 +972,36 @@ public class NewContactScreen: ViewControllerComponentContainer {
noteEntities: entities
).startStandalone()
}
if result.syncContactToPhone, let contactDataManager = self.context.sharedContext.contactDataManager {
let composedContactData = DeviceContactExtendedData(
basicData: DeviceContactBasicData(
firstName: result.firstName,
lastName: result.lastName,
phoneNumbers: [
DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: result.phoneNumber)
]
),
middleName: "",
prefix: "",
suffix: "",
organization: "",
jobTitle: "",
department: "",
emailAddresses: [],
urls: [],
addresses: [],
birthdayDate: nil,
socialProfiles: [],
instantMessagingProfiles: [],
note: ""
)
let _ = (contactDataManager.createContactWithData(composedContactData)
|> deliverOnMainQueue).start(next: { [weak self] contactIdAndData in
if let self, let contactIdAndData {
self.completion(result.peer, contactIdAndData.0, contactIdAndData.1)
}
})
}
}
}

View file

@ -626,15 +626,21 @@ public final class GiftItemComponent: Component {
let price: String
switch component.subject {
case let .premium(_, priceValue), let .starGift(_, priceValue):
if priceValue.contains("#") {
if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction) {
buttonColor = component.theme.overallDarkAppearance ? UIColor(rgb: 0xffc337) : UIColor(rgb: 0xd3720a)
if !component.isSoldOut {
starsColor = UIColor(rgb: 0xffbe27)
}
//todo:localize
price = "Place a Bid"
} else {
buttonColor = component.theme.list.itemAccentColor
if priceValue.contains("#") {
buttonColor = component.theme.overallDarkAppearance ? UIColor(rgb: 0xffc337) : UIColor(rgb: 0xd3720a)
if !component.isSoldOut {
starsColor = UIColor(rgb: 0xffbe27)
}
} else {
buttonColor = component.theme.list.itemAccentColor
}
price = priceValue
}
price = priceValue
case let .uniqueGift(_, priceValue):
if let ribbon = component.ribbon, case let .custom(bottomValue, topValue) = ribbon.color {
let topColor = UIColor(rgb: UInt32(bitPattern: topValue)).withMultiplied(hue: 1.01, saturation: 1.22, brightness: 1.04)

View file

@ -520,19 +520,28 @@ final class GiftOptionsScreenComponent: Component {
isSoldOut = true
} else if let _ = gift.availability {
let text: String
if let perUserLimit = gift.perUserLimit {
var ribbonColor: GiftItemComponent.Ribbon.Color = .blue
if gift.flags.contains(.isAuction) {
//TODO:localize
text = "auction"
ribbonColor = .orange
outline = .orange
} else if let perUserLimit = gift.perUserLimit {
text = environment.strings.Gift_Options_Gift_Limited_Left(perUserLimit.remains)
} else {
text = environment.strings.Gift_Options_Gift_Limited
}
ribbon = GiftItemComponent.Ribbon(
text: text,
color: .blue
color: ribbonColor
)
}
if !isSoldOut && gift.flags.contains(.requiresPremium) {
let text: String
if component.context.isPremium, let perUserLimit = gift.perUserLimit {
if gift.flags.contains(.isAuction) {
//TODO:localize
text = "auction"
} else if component.context.isPremium, let perUserLimit = gift.perUserLimit {
text = environment.strings.Gift_Options_Gift_Premium_Left(perUserLimit.remains)
} else {
text = environment.strings.Gift_Options_Gift_Premium

View file

@ -49,6 +49,8 @@ swift_library(
"//submodules/TelegramUI/Components/Gifts/GiftViewScreen",
"//submodules/ConfettiEffect",
"//submodules/TelegramUI/Components/EdgeEffect",
"//submodules/TelegramUI/Components/AnimatedTextComponent",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
],
visibility = [
"//visibility:public",

View file

@ -233,7 +233,7 @@ final class ChatGiftPreviewItemNode: ListViewItemNode {
case let .premium(months, amount, currency):
media = [
TelegramMediaAction(
action: .giftPremium(currency: currency, amount: amount, months: months, cryptoCurrency: nil, cryptoAmount: nil, text: item.text, entities: item.entities)
action: .giftPremium(currency: currency, amount: amount, days: months * 30, cryptoCurrency: nil, cryptoAmount: nil, text: item.text, entities: item.entities)
)
]
case let .starGift(gift):

View file

@ -37,6 +37,7 @@ import GiftViewScreen
import UndoUI
import ConfettiEffect
import EdgeEffect
import AnimatedTextComponent
final class GiftSetupScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -83,6 +84,7 @@ final class GiftSetupScreenComponent: Component {
private let navigationTitle = ComponentView<Empty>()
private let remainingCount = ComponentView<Empty>()
private let auctionFooter = ComponentView<Empty>()
private let resaleSection = ComponentView<Empty>()
private let introContent = ComponentView<Empty>()
private let introSection = ComponentView<Empty>()
@ -133,6 +135,11 @@ final class GiftSetupScreenComponent: Component {
private var peerMap: [EnginePeer.Id: EnginePeer] = [:]
private var sendPaidMessageStars: StarsAmount?
private var giftAuction: GiftAuctionContext?
private var giftAuctionState: GiftAuctionContext.State?
private var giftAuctionDisposable: Disposable?
private var giftAuctionTimer: SwiftSignalKit.Timer?
private var starImage: (UIImage, PresentationTheme)?
private var updateDisposable: Disposable?
@ -183,6 +190,8 @@ final class GiftSetupScreenComponent: Component {
self.inputMediaNodeDataDisposable?.dispose()
self.updateDisposable?.dispose()
self.optionsDisposable?.dispose()
self.giftAuctionDisposable?.dispose()
self.giftAuctionTimer?.invalidate()
}
func scrollToTop() {
@ -230,11 +239,37 @@ final class GiftSetupScreenComponent: Component {
self.buttonSeparator.opacity = Float(bottomPanelAlpha)
}
private var openedAuction: Bool = false
@objc private func proceed() {
guard let component = self.component, let environment = self.environment else {
return
}
if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let navigationController = environment.controller()?.navigationController as? NavigationController {
let giftAuction = self.giftAuction
let openAuction = { [weak giftAuction, weak navigationController] in
guard let giftAuction, let navigationController else {
return
}
let controller = component.context.sharedContext.makeGiftAuctionScreen(context: component.context, gift: .generic(gift), auctionContext: giftAuction)
navigationController.pushViewController(controller)
}
if self.openedAuction {
openAuction()
} else {
self.openedAuction = true
let controller = component.context.sharedContext.makeGiftAuctionInfoScreen(context: component.context, gift: .generic(gift), completion: {
openAuction()
})
environment.controller()?.push(controller)
}
return
}
switch component.subject {
case let .premium(product):
if self.payWithStars, let starsPrice = product.starsPrice, let peer = self.peerMap[component.peerId] {
@ -618,6 +653,24 @@ 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)
self.giftAuction = giftAuction
self.giftAuctionDisposable = (giftAuction.state
|> deliverOnMainQueue).start(next: { [weak self] state in
guard let self else {
return
}
self.giftAuctionState = state
self.state?.updated()
})
self.giftAuctionTimer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
self?.state?.updated()
}, queue: Queue.mainQueue())
self.giftAuctionTimer?.start()
}
var releasedBy: EnginePeer.Id?
if case let .starGift(gift, true) = component.subject, gift.upgradeStars != nil {
self.includeUpgrade = true
@ -830,45 +883,7 @@ final class GiftSetupScreenComponent: Component {
contentHeight += environment.navigationHeight
contentHeight += 26.0
if case let .starGift(starGift, _) = component.subject, let availability = starGift.availability {
let remains: Int32 = availability.remains
let total: Int32 = availability.total
let position = CGFloat(remains) / CGFloat(total)
let sold = total - remains
let remainingCountSize = self.remainingCount.update(
transition: transition,
component: AnyComponent(RemainingCountComponent(
inactiveColor: environment.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.3),
activeColors: [UIColor(rgb: 0x5bc2ff), UIColor(rgb: 0x2d9eff)],
inactiveTitle: environment.strings.Gift_Send_Remains(remains),
inactiveValue: "",
inactiveTitleColor: environment.theme.list.itemSecondaryTextColor,
activeTitle: "",
activeValue: environment.strings.Gift_Send_Sold(sold),//totalString,
activeTitleColor: .white,
badgeText: "",
badgePosition: position,
badgeGraphPosition: position,
invertProgress: true,
leftString: "",
groupingSeparator: environment.dateTimeFormat.groupingSeparator
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
)
let remainingCountFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight - 77.0), size: remainingCountSize)
if let remainingCountView = self.remainingCount.view {
if remainingCountView.superview == nil {
self.scrollView.addSubview(remainingCountView)
}
transition.setFrame(view: remainingCountView, frame: remainingCountFrame)
}
contentHeight += remainingCountSize.height
contentHeight -= 77.0
contentHeight += sectionSpacing
}
if case let .starGift(starGift, forceUnique) = component.subject, let availability = starGift.availability, availability.resale > 0 {
if let forceUnique, !forceUnique {
} else {
@ -1381,8 +1396,96 @@ final class GiftSetupScreenComponent: Component {
}
contentHeight += hideSectionSize.height
}
contentHeight += sectionSpacing
if case let .starGift(starGift, _) = component.subject, let availability = starGift.availability {
contentHeight -= 77.0
contentHeight += 16.0
contentHeight += 24.0
let remains: Int32 = availability.remains
let total: Int32 = availability.total
let position = CGFloat(remains) / CGFloat(total)
let sold = total - remains
let remainingCountSize = self.remainingCount.update(
transition: transition,
component: AnyComponent(RemainingCountComponent(
inactiveColor: environment.theme.list.itemBlocksSeparatorColor.withAlphaComponent(0.3),
activeColors: [UIColor(rgb: 0x5bc2ff), UIColor(rgb: 0x2d9eff)],
inactiveTitle: environment.strings.Gift_Send_Remains(remains),
inactiveValue: "",
inactiveTitleColor: environment.theme.list.itemSecondaryTextColor,
activeTitle: "",
activeValue: environment.strings.Gift_Send_Sold(sold),//totalString,
activeTitleColor: .white,
badgeText: "",
badgePosition: position,
badgeGraphPosition: position,
invertProgress: true,
leftString: "",
groupingSeparator: environment.dateTimeFormat.groupingSeparator
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
)
let remainingCountFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: remainingCountSize)
if let remainingCountView = self.remainingCount.view {
if remainingCountView.superview == nil {
self.scrollView.addSubview(remainingCountView)
}
transition.setFrame(view: remainingCountView, frame: remainingCountFrame)
}
contentHeight += remainingCountSize.height
contentHeight += 7.0
if starGift.flags.contains(.isAuction) {
let parsedString = parseMarkdownIntoAttributedString("50 gifts are dropped at varying intervals to the top 50 bidders by bid amount. [Learn more >]()", attributes: footerAttributes)
let auctionFooterText = NSMutableAttributedString(attributedString: parsedString)
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
}
if let range = auctionFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 {
auctionFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: auctionFooterText.string))
}
let auctionFooterSize = self.auctionFooter.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
text: .plain(auctionFooterText),
maximumNumberOfLines: 0,
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
highlightAction: { attributes in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
} else {
return nil
}
},
tapAction: { [weak self] _, _ in
guard let self, let component = self.component, case let .starGift(gift, _) = component.subject, let controller = self.environment?.controller() else {
return
}
let infoController = component.context.sharedContext.makeGiftAuctionInfoScreen(context: component.context, gift: .generic(gift), completion: nil)
controller.push(infoController)
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 16.0 * 2.0, height: 10000.0)
)
let auctionFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: auctionFooterSize)
if let auctionFooterView = self.auctionFooter.view {
if auctionFooterView.superview == nil {
self.scrollView.addSubview(auctionFooterView)
}
transition.setFrame(view: auctionFooterView, frame: auctionFooterFrame)
}
contentHeight += remainingCountSize.height
}
contentHeight += sectionSpacing
}
let buttonHeight: CGFloat = 50.0
let bottomPanelPadding: CGFloat = 12.0
@ -1439,6 +1542,8 @@ final class GiftSetupScreenComponent: Component {
}
}
var buttonTitleItems: [AnyComponentWithIdentity<Empty>] = []
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.starImage?.0 {
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
@ -1447,9 +1552,71 @@ final class GiftSetupScreenComponent: Component {
buttonAttributedString.addAttribute(.kern, value: 2.0, range: NSRange(range, in: buttonAttributedString.string))
}
var buttonIsLoading = false
if let _ = self.giftAuction {
//TODO:localize
let buttonAttributedString = NSMutableAttributedString(string: "Place a Bid", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
buttonTitleItems.append(AnyComponentWithIdentity(id: "bid", component: AnyComponent(
MultilineTextComponent(text: .plain(buttonAttributedString))
)))
if let giftAuctionState = self.giftAuctionState {
switch giftAuctionState.auctionState {
case let .ongoing(_, _, _, _, _, nextDropDate, _, _):
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
let dropTimeout = nextDropDate - currentTime
let minutes = Int(dropTimeout / 60)
let seconds = Int(dropTimeout % 60)
let rawString = environment.strings.Gift_Setup_NextDropIn
var buttonAnimatedTitleItems: [AnimatedTextComponent.Item] = []
var startIndex = rawString.startIndex
while true {
if let range = rawString.range(of: "{", range: startIndex ..< rawString.endIndex) {
if range.lowerBound != startIndex {
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< range.lowerBound]))))
}
startIndex = range.upperBound
if let endRange = rawString.range(of: "}", range: startIndex ..< rawString.endIndex) {
let controlString = rawString[range.upperBound ..< endRange.lowerBound]
if controlString == "m" {
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(minutes, minDigits: 2)))
} else if controlString == "s" {
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(seconds, minDigits: 2)))
}
startIndex = endRange.upperBound
}
} else {
break
}
}
if startIndex != rawString.endIndex {
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< rawString.endIndex]))))
}
buttonTitleItems.append(AnyComponentWithIdentity(id: "timer", component: AnyComponent(AnimatedTextComponent(
font: Font.with(size: 12.0, weight: .medium, traits: .monospacedNumbers),
color: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7),
items: buttonAnimatedTitleItems,
noDelay: true
))))
case .finished:
buttonIsEnabled = false
}
} else {
buttonIsLoading = true
}
} else {
buttonTitleItems.append(AnyComponentWithIdentity(id: buttonString, component: AnyComponent(
MultilineTextComponent(text: .plain(buttonAttributedString))
)))
}
let buttonSideInset = environment.safeInsets.left + 36.0
let buttonSize = self.button.update(
transition: transition,
transition: .spring(duration: 0.2),
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
@ -1459,11 +1626,11 @@ final class GiftSetupScreenComponent: Component {
isShimmering: true
),
content: AnyComponentWithIdentity(
id: AnyHashable(buttonString),
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
id: AnyHashable("title"),
component: AnyComponent(VStack(buttonTitleItems, spacing: 1.0))
),
isEnabled: buttonIsEnabled,
displaysProgress: self.inProgress,
displaysProgress: buttonIsLoading || self.inProgress,
action: { [weak self] in
self?.proceed()
}

View file

@ -12,6 +12,7 @@ import MultilineTextComponent
import Markdown
import TextFormat
import RoundedRectWithTailPath
import GlassBackgroundComponent
public class RemainingCountComponent: Component {
private let inactiveColor: UIColor
@ -125,22 +126,12 @@ public class RemainingCountComponent: Component {
private let activeTitleLabel = ComponentView<Empty>()
private let activeValueLabel = ComponentView<Empty>()
private let badgeView: UIView
private let badgeMaskView: UIView
private let badgeShapeLayer = CAShapeLayer()
private let badgeForeground: SimpleLayer
private var badgeLabel: BadgeLabelView?
private let badgeLeftLabel = ComponentView<Empty>()
private let badgeLabelMaskView = UIImageView()
private var badgeTailPosition: CGFloat = 0.0
private var badgeShapeArguments: (Double, Double, CGSize, CGFloat, CGFloat)?
private let activeChromeView = UIImageView()
override init(frame: CGRect) {
self.container = UIView()
self.container.clipsToBounds = true
self.container.layer.cornerRadius = 9.0
self.container.layer.cornerRadius = 15.0
self.inactiveBackground = SimpleLayer()
@ -149,18 +140,6 @@ public class RemainingCountComponent: Component {
self.activeBackground = SimpleLayer()
self.activeBackground.anchorPoint = CGPoint()
self.badgeView = UIView()
self.badgeView.alpha = 0.0
self.badgeShapeLayer.fillColor = UIColor.white.cgColor
self.badgeShapeLayer.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.badgeMaskView = UIView()
self.badgeMaskView.layer.addSublayer(self.badgeShapeLayer)
self.badgeView.mask = self.badgeMaskView
self.badgeForeground = SimpleLayer()
super.init(frame: frame)
@ -168,27 +147,11 @@ public class RemainingCountComponent: Component {
self.container.layer.addSublayer(self.inactiveBackground)
self.container.addSubview(self.activeContainer)
self.activeContainer.layer.addSublayer(self.activeBackground)
self.activeContainer.addSubview(self.activeChromeView)
//self.addSubview(self.badgeView)
self.badgeView.layer.addSublayer(self.badgeForeground)
//self.badgeView.addSubview(self.badgeLabel)
self.badgeLabelMaskView.contentMode = .scaleToFill
self.badgeLabelMaskView.image = generateImage(CGSize(width: 2.0, height: 30.0), rotatedContext: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
let colorsArray: [CGColor] = [
UIColor(rgb: 0xffffff, alpha: 0.0).cgColor,
UIColor(rgb: 0xffffff).cgColor,
UIColor(rgb: 0xffffff).cgColor,
UIColor(rgb: 0xffffff, alpha: 0.0).cgColor,
]
var locations: [CGFloat] = [0.0, 0.24, 0.76, 1.0]
let gradient = CGGradient(colorsSpace: deviceColorSpace, colors: colorsArray as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
})
self.activeChromeView.layer.compositingFilter = "overlayBlendMode"
self.activeChromeView.alpha = 0.8
self.activeChromeView.image = GlassBackgroundView.generateForegroundImage(size: CGSize(width: 30.0, height: 30.0), isDark: false, fillColor: .clear)
self.isUserInteractionEnabled = false
}
@ -197,83 +160,6 @@ public class RemainingCountComponent: Component {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.badgeShapeAnimator?.invalidate()
}
private var didPlayAppearanceAnimation = false
func playAppearanceAnimation(component: RemainingCountComponent, badgeFullSize: CGSize, from: CGFloat? = nil) {
if from == nil {
self.badgeView.layer.animateScale(from: 0.1, to: 1.0, duration: 0.4, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
}
let rotationAngle: CGFloat
if badgeFullSize.width > 100.0 {
rotationAngle = 0.2
} else {
rotationAngle = 0.26
}
let to: CGFloat = self.badgeView.center.x
let positionAnimation = CABasicAnimation(keyPath: "position.x")
positionAnimation.fromValue = NSValue(cgPoint: CGPoint(x: from ?? self.container.frame.width, y: 0.0))
positionAnimation.toValue = NSValue(cgPoint: CGPoint(x: to, y: 0.0))
positionAnimation.duration = 0.5
positionAnimation.fillMode = .forwards
positionAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
self.badgeView.layer.add(positionAnimation, forKey: "appearance1")
if from != to {
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotateAnimation.fromValue = 0.0 as NSNumber
rotateAnimation.toValue = rotationAngle as NSNumber
rotateAnimation.duration = 0.15
rotateAnimation.fillMode = .forwards
rotateAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
rotateAnimation.isRemovedOnCompletion = false
self.badgeView.layer.add(rotateAnimation, forKey: "appearance2")
Queue.mainQueue().after(0.5, {
let bounceAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
bounceAnimation.fromValue = rotationAngle as NSNumber
bounceAnimation.toValue = -0.04 as NSNumber
bounceAnimation.duration = 0.2
bounceAnimation.fillMode = .forwards
bounceAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
bounceAnimation.isRemovedOnCompletion = false
self.badgeView.layer.add(bounceAnimation, forKey: "appearance3")
self.badgeView.layer.removeAnimation(forKey: "appearance2")
Queue.mainQueue().after(0.2) {
let returnAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
returnAnimation.fromValue = -0.04 as NSNumber
returnAnimation.toValue = 0.0 as NSNumber
returnAnimation.duration = 0.15
returnAnimation.fillMode = .forwards
returnAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
self.badgeView.layer.add(returnAnimation, forKey: "appearance4")
self.badgeView.layer.removeAnimation(forKey: "appearance3")
}
})
}
if from == nil {
self.badgeView.alpha = 1.0
self.badgeView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
}
if let badgeText = component.badgeText, let badgeLabel = self.badgeLabel {
let transition: ComponentTransition = .easeInOut(duration: from != nil ? 0.3 : 0.5)
var frameTransition = transition
if from == nil {
frameTransition = frameTransition.withAnimation(.none)
}
let badgeLabelSize = badgeLabel.update(value: badgeText, transition: transition)
frameTransition.setFrame(view: badgeLabel, frame: CGRect(origin: CGPoint(x: 10.0, y: -2.0), size: badgeLabelSize))
}
}
var previousAvailableSize: CGSize?
func update(component: RemainingCountComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize {
self.component = component
@ -282,17 +168,6 @@ public class RemainingCountComponent: Component {
let size = CGSize(width: availableSize.width, height: 90.0)
if self.badgeLabel == nil {
let badgeLabel = BadgeLabelView(groupingSeparator: component.groupingSeparator)
let _ = badgeLabel.update(value: "0", transition: .immediate)
badgeLabel.mask = self.badgeLabelMaskView
self.badgeLabel = badgeLabel
self.badgeView.addSubview(badgeLabel)
}
self.badgeLabel?.color = component.activeTitleColor
let lineHeight: CGFloat = 30.0
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - lineHeight), size: CGSize(width: size.width, height: lineHeight))
self.container.frame = containerFrame
@ -468,129 +343,14 @@ public class RemainingCountComponent: Component {
progressTransition.setFrame(view: self.activeContainer, frame: CGRect(origin: CGPoint(x: activityPosition, y: 0.0), size: CGSize(width: activeWidth, height: lineHeight)))
progressTransition.setFrame(layer: self.activeBackground, frame: CGRect(origin: CGPoint(x: -activityPosition, y: 0.0), size: CGSize(width: containerFrame.width * 1.35, height: lineHeight)))
}
progressTransition.setFrame(view: self.activeChromeView, frame: CGRect(origin: CGPoint(x: -activityPosition, y: 0.0), size: CGSize(width: activeWidth, height: lineHeight)))
if self.activeBackground.animation(forKey: "movement") == nil {
self.activeBackground.position = CGPoint(x: -self.activeContainer.frame.width * 0.35, y: lineHeight / 2.0)
}
}
let countWidth: CGFloat
if let badgeText = component.badgeText {
countWidth = getLabelWidth(badgeText)
} else {
countWidth = 51.0
}
let badgeSpacing: CGFloat = 4.0
let badgeLeftSize = self.badgeLeftLabel.update(
transition: .immediate,
component: AnyComponent(
MultilineTextComponent(
text: .plain(
NSAttributedString(
string: component.leftString,
font: Font.semibold(15.0),
textColor: component.activeTitleColor
)
)
)
),
environment: {},
containerSize: availableSize
)
if let view = self.badgeLeftLabel.view {
if view.superview == nil {
self.badgeView.addSubview(view)
}
view.frame = CGRect(origin: CGPoint(x: 10.0 + countWidth + badgeSpacing, y: 4.0 + UIScreenPixel), size: badgeLeftSize)
}
let badgeWidth: CGFloat = countWidth + 20.0 + badgeSpacing + badgeLeftSize.width
let badgeSize = CGSize(width: badgeWidth, height: 30.0)
let badgeFullSize = CGSize(width: badgeWidth, height: badgeSize.height + 8.0)
let tailSize = CGSize(width: 15.0, height: 6.0)
let tailRadius: CGFloat = 3.0
self.badgeMaskView.frame = CGRect(origin: .zero, size: badgeFullSize)
self.badgeShapeLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -4.0), size: badgeFullSize)
self.badgeView.bounds = CGRect(origin: .zero, size: badgeFullSize)
let currentBadgeX = self.badgeView.center.x
let badgePosition = component.badgePosition
if badgePosition > 1.0 - 0.15 {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 1.0, y: 1.0))
if progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailSize: tailSize, tailRadius: tailRadius, tailPosition: 1.0).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 1.0)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 1.0
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: 3.0 + (size.width - 6.0) * badgePosition + 3.0, y: 56.0)
}
} else if badgePosition < 0.15 {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 0.0, y: 1.0))
if progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailSize: tailSize, tailRadius: tailRadius, tailPosition: 0.0).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 0.0)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 0.0
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: (size.width - 6.0) * badgePosition, y: 56.0)
}
} else {
progressTransition.setAnchorPoint(layer: self.badgeView.layer, anchorPoint: CGPoint(x: 0.5, y: 1.0))
if progressTransition.animation.isImmediate {
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailSize: tailSize, tailRadius: tailRadius, tailPosition: 0.5).cgPath
} else {
self.badgeShapeArguments = (CACurrentMediaTime(), 0.5, badgeSize, self.badgeTailPosition, 0.5)
self.animateBadgeTailPositionChange()
}
self.badgeTailPosition = 0.5
if let _ = self.badgeView.layer.animation(forKey: "appearance1") {
} else {
self.badgeView.center = CGPoint(x: size.width * badgePosition, y: 56.0)
}
}
self.badgeForeground.bounds = CGRect(origin: CGPoint(), size: CGSize(width: badgeFullSize.width * 3.0, height: badgeFullSize.height))
if self.badgeForeground.animation(forKey: "movement") == nil {
self.badgeForeground.position = CGPoint(x: badgeSize.width * 3.0 / 2.0 - self.badgeForeground.frame.width * 0.35, y: badgeFullSize.height / 2.0)
}
self.badgeLabelMaskView.frame = CGRect(x: 0.0, y: 0.0, width: 100.0, height: 36.0)
if !self.didPlayAppearanceAnimation || !transition.animation.isImmediate {
self.didPlayAppearanceAnimation = true
if transition.animation.isImmediate {
if component.badgePosition < 0.1 {
self.badgeView.alpha = 1.0
if let badgeText = component.badgeText, let badgeLabel = self.badgeLabel {
let badgeLabelSize = badgeLabel.update(value: badgeText, transition: .immediate)
transition.setFrame(view: badgeLabel, frame: CGRect(origin: CGPoint(x: 10.0, y: -2.0), size: badgeLabelSize))
}
} else {
self.playAppearanceAnimation(component: component, badgeFullSize: badgeFullSize)
}
} else {
self.playAppearanceAnimation(component: component, badgeFullSize: badgeFullSize, from: currentBadgeX)
}
}
if self.previousAvailableSize != availableSize {
self.previousAvailableSize = availableSize
@ -600,9 +360,7 @@ public class RemainingCountComponent: Component {
locations.append(delta * CGFloat(i))
}
let gradient = generateGradientImage(size: CGSize(width: 200.0, height: 60.0), colors: component.activeColors, locations: locations, direction: .horizontal)
self.badgeForeground.contentsGravity = .resizeAspectFill
self.badgeForeground.contents = gradient?.cgImage
let gradient = generateGradientImage(size: CGSize(width: 200.0, height: 60.0), colors: Array(component.activeColors.reversed()), locations: locations, direction: .horizontal)
self.activeBackground.contentsGravity = .resizeAspectFill
self.activeBackground.contents = gradient?.cgImage
@ -613,54 +371,14 @@ public class RemainingCountComponent: Component {
return size
}
private var badgeShapeAnimator: ConstantDisplayLinkAnimator?
private func animateBadgeTailPositionChange() {
if self.badgeShapeAnimator == nil {
self.badgeShapeAnimator = ConstantDisplayLinkAnimator(update: { [weak self] in
self?.animateBadgeTailPositionChange()
})
self.badgeShapeAnimator?.isPaused = true
}
if let (startTime, duration, badgeSize, initial, target) = self.badgeShapeArguments {
self.badgeShapeAnimator?.isPaused = false
let t = CGFloat(max(0.0, min(1.0, (CACurrentMediaTime() - startTime) / duration)))
let value = initial + (target - initial) * t
let tailSize = CGSize(width: 15.0, height: 6.0)
let tailRadius: CGFloat = 3.0
self.badgeShapeLayer.path = generateRoundedRectWithTailPath(rectSize: badgeSize, tailSize: tailSize, tailRadius: tailRadius, tailPosition: value).cgPath
if t >= 1.0 {
self.badgeShapeArguments = nil
self.badgeShapeAnimator?.isPaused = true
self.badgeShapeAnimator?.invalidate()
self.badgeShapeAnimator = nil
}
} else {
self.badgeShapeAnimator?.isPaused = true
self.badgeShapeAnimator?.invalidate()
self.badgeShapeAnimator = nil
}
}
private func setupGradientAnimations() {
guard let _ = self.component else {
return
}
if let _ = self.badgeForeground.animation(forKey: "movement") {
if let _ = self.activeBackground.animation(forKey: "movement") {
} else {
CATransaction.begin()
let badgeOffset = (self.badgeForeground.frame.width - self.badgeView.bounds.width) / 2.0
let badgePreviousValue = self.badgeForeground.position.x
var badgeNewValue: CGFloat = badgeOffset
if badgeOffset - badgePreviousValue < self.badgeForeground.frame.width * 0.25 {
badgeNewValue -= self.badgeForeground.frame.width * 0.35
}
self.badgeForeground.position = CGPoint(x: badgeNewValue, y: self.badgeForeground.bounds.size.height / 2.0)
let lineOffset = 0.0
let linePreviousValue = self.activeBackground.position.x
var lineNewValue: CGFloat = lineOffset
@ -671,18 +389,7 @@ public class RemainingCountComponent: Component {
}
lineNewValue -= self.activeContainer.frame.minX
self.activeBackground.position = CGPoint(x: lineNewValue, y: 0.0)
let badgeAnimation = CABasicAnimation(keyPath: "position.x")
badgeAnimation.duration = 4.5
badgeAnimation.fromValue = badgePreviousValue
badgeAnimation.toValue = badgeNewValue
badgeAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
CATransaction.setCompletionBlock { [weak self] in
self?.setupGradientAnimations()
}
self.badgeForeground.add(badgeAnimation, forKey: "movement")
let lineAnimation = CABasicAnimation(keyPath: "position.x")
lineAnimation.duration = 4.5
lineAnimation.fromValue = linePreviousValue
@ -703,181 +410,3 @@ public class RemainingCountComponent: Component {
return view.update(component: self, availableSize: availableSize, transition: transition)
}
}
private let spaceWidth: CGFloat = 3.0
private let labelWidth: CGFloat = 10.0
private let labelHeight: CGFloat = 30.0
private let labelSize = CGSize(width: labelWidth, height: labelHeight)
private let font = Font.with(size: 15.0, design: .regular, weight: .semibold, traits: [])
final class BadgeLabelView: UIView {
private class StackView: UIView {
var labels: [UILabel] = []
var currentValue: Int32?
var color: UIColor = .white {
didSet {
for view in self.labels {
view.textColor = self.color
}
}
}
init(groupingSeparator: String) {
super.init(frame: CGRect(origin: .zero, size: labelSize))
var height: CGFloat = -labelHeight * 2.0
for i in -2 ..< 10 {
let label = UILabel()
let itemWidth: CGFloat
if i == -2 {
label.text = groupingSeparator
itemWidth = spaceWidth
} else if i == -1 {
label.text = "9"
itemWidth = labelWidth
} else {
label.text = "\(i)"
itemWidth = labelWidth
}
label.textColor = self.color
label.font = font
label.textAlignment = .center
label.frame = CGRect(x: 0, y: height, width: itemWidth, height: labelHeight)
self.addSubview(label)
self.labels.append(label)
height += labelHeight
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(value: Int32?, isFirst: Bool, isLast: Bool, transition: ComponentTransition) {
let previousValue = self.currentValue
self.currentValue = value
self.labels[2].alpha = isFirst && !isLast ? 0.0 : 1.0
if let value {
if previousValue == 9 && value < 9 {
self.bounds = CGRect(
origin: CGPoint(
x: 0.0,
y: -1.0 * labelSize.height
),
size: labelSize
)
}
let bounds = CGRect(
origin: CGPoint(
x: 0.0,
y: CGFloat(value) * labelSize.height
),
size: labelSize
)
transition.setBounds(view: self, bounds: bounds)
} else {
self.bounds = CGRect(
origin: CGPoint(
x: 0.0,
y: -2.0 * labelSize.height
),
size: labelSize
)
}
}
}
private let groupingSeparator: String
private var itemViews: [Int: StackView] = [:]
init(groupingSeparator: String) {
self.groupingSeparator = groupingSeparator
super.init(frame: .zero)
self.clipsToBounds = true
self.isUserInteractionEnabled = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var color: UIColor = .white {
didSet {
for (_, view) in self.itemViews {
view.color = self.color
}
}
}
func update(value: String, transition: ComponentTransition) -> CGSize {
let string = value
let stringArray = Array(string.map { String($0) }.reversed())
let totalWidth: CGFloat = getLabelWidth(value)
var rightX: CGFloat = totalWidth
var validIds: [Int] = []
for i in 0 ..< stringArray.count {
validIds.append(i)
let itemView: StackView
var itemTransition = transition
if let current = self.itemViews[i] {
itemView = current
} else {
itemTransition = transition.withAnimation(.none)
itemView = StackView(groupingSeparator: self.groupingSeparator)
itemView.color = self.color
self.itemViews[i] = itemView
self.addSubview(itemView)
}
let digit = Int32(stringArray[i])
itemView.update(value: digit, isFirst: i == stringArray.count - 1, isLast: i == 0, transition: transition)
let itemWidth: CGFloat = digit != nil ? labelWidth : spaceWidth
rightX -= itemWidth
itemTransition.setFrame(
view: itemView,
frame: CGRect(x: rightX, y: 0.0, width: labelWidth, height: labelHeight)
)
}
var removeIds: [Int] = []
for (id, itemView) in self.itemViews {
if !validIds.contains(id) {
removeIds.append(id)
transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
itemView.removeFromSuperview()
})
}
}
for id in removeIds {
self.itemViews.removeValue(forKey: id)
}
return CGSize(width: totalWidth, height: labelHeight)
}
}
private func getLabelWidth(_ string: String) -> CGFloat {
var totalWidth: CGFloat = 0.0
for c in string {
if CharacterSet.decimalDigits.contains(c.unicodeScalars[c.unicodeScalars.startIndex]) {
totalWidth += labelWidth
} else {
totalWidth += spaceWidth
}
}
return totalWidth
}

View file

@ -56,6 +56,10 @@ swift_library(
"//submodules/TelegramUI/Components/ChatThemeScreen",
"//submodules/ImageBlur",
"//submodules/TelegramUI/Components/PeerInfo/ProfileLevelRatingBarComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/Stories/LiveChat/StoryLiveChatMessageComponent",
"//submodules/TelegramUI/Components/AnimatedTextComponent",
"//submodules/BotPaymentsUI",
],
visibility = [
"//visibility:public",

View file

@ -0,0 +1,166 @@
import Foundation
import UIKit
import Display
import ComponentFlow
private let labelWidth: CGFloat = 16.0
private let labelHeight: CGFloat = 36.0
private let labelSize = CGSize(width: labelWidth, height: labelHeight)
private let font = Font.with(size: 24.0, design: .round, weight: .semibold, traits: [])
final class BadgeLabelView: UIView {
private class StackView: UIView {
var labels: [UILabel] = []
var currentValue: Int32 = 0
var color: UIColor = .white {
didSet {
for view in self.labels {
view.textColor = self.color
}
}
}
init() {
super.init(frame: CGRect(origin: .zero, size: labelSize))
var height: CGFloat = -labelHeight
for i in -1 ..< 10 {
let label = UILabel()
if i == -1 {
label.text = "9"
} else {
label.text = "\(i)"
}
label.textColor = self.color
label.font = font
label.textAlignment = .center
label.frame = CGRect(x: 0, y: height, width: labelWidth, height: labelHeight)
self.addSubview(label)
self.labels.append(label)
height += labelHeight
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(value: Int32, isFirst: Bool, isLast: Bool, transition: ComponentTransition) {
let previousValue = self.currentValue
self.currentValue = value
self.labels[1].alpha = isFirst && !isLast ? 0.0 : 1.0
if previousValue == 9 && value < 9 {
self.bounds = CGRect(
origin: CGPoint(
x: 0.0,
y: -1.0 * labelSize.height
),
size: labelSize
)
}
let bounds = CGRect(
origin: CGPoint(
x: 0.0,
y: CGFloat(value) * labelSize.height
),
size: labelSize
)
transition.setBounds(view: self, bounds: bounds)
}
}
private var itemViews: [Int: StackView] = [:]
private var staticLabel = UILabel()
init() {
super.init(frame: .zero)
self.clipsToBounds = true
self.isUserInteractionEnabled = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var color: UIColor = .white {
didSet {
self.staticLabel.textColor = self.color
for (_, view) in self.itemViews {
view.color = self.color
}
}
}
func update(value: String, transition: ComponentTransition) -> CGSize {
if value.contains(" ") {
for (_, view) in self.itemViews {
view.isHidden = true
}
if self.staticLabel.superview == nil {
self.staticLabel.textColor = self.color
self.staticLabel.font = font
self.addSubview(self.staticLabel)
}
self.staticLabel.text = value
let size = self.staticLabel.sizeThatFits(CGSize(width: 100.0, height: 100.0))
self.staticLabel.frame = CGRect(origin: .zero, size: CGSize(width: size.width, height: labelHeight))
return CGSize(width: ceil(self.staticLabel.bounds.width), height: ceil(self.staticLabel.bounds.height))
}
let string = value
let stringArray = Array(string.map { String($0) }.reversed())
let totalWidth = CGFloat(stringArray.count) * labelWidth
var validIds: [Int] = []
for i in 0 ..< stringArray.count {
validIds.append(i)
let itemView: StackView
var itemTransition = transition
if let current = self.itemViews[i] {
itemView = current
} else {
itemTransition = transition.withAnimation(.none)
itemView = StackView()
itemView.color = self.color
self.itemViews[i] = itemView
self.addSubview(itemView)
}
let digit = Int32(stringArray[i]) ?? 0
itemView.update(value: digit, isFirst: i == stringArray.count - 1, isLast: i == 0, transition: transition)
itemTransition.setFrame(
view: itemView,
frame: CGRect(x: totalWidth - labelWidth * CGFloat(i + 1), y: 0.0, width: labelWidth, height: labelHeight)
)
}
var removeIds: [Int] = []
for (id, itemView) in self.itemViews {
if !validIds.contains(id) {
removeIds.append(id)
transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in
itemView.removeFromSuperview()
})
}
}
for id in removeIds {
self.itemViews.removeValue(forKey: id)
}
return CGSize(width: totalWidth, height: labelHeight)
}
}

View file

@ -0,0 +1,646 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
import AccountContext
import TelegramPresentationData
import PresentationDataUtils
import ComponentFlow
import ViewControllerComponent
import SheetComponent
import MultilineTextComponent
import BalancedTextComponent
import BundleIconComponent
import Markdown
import TextFormat
import TelegramStringFormatting
import GiftAnimationComponent
import GlassBarButtonComponent
import ButtonComponent
import LottieComponent
private final class GiftAuctionInfoSheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let gift: StarGift
let animateOut: ActionSlot<Action<()>>
let getController: () -> ViewController?
init(
context: AccountContext,
gift: StarGift,
animateOut: ActionSlot<Action<()>>,
getController: @escaping () -> ViewController?
) {
self.context = context
self.gift = gift
self.animateOut = animateOut
self.getController = getController
}
static func ==(lhs: GiftAuctionInfoSheetContent, rhs: GiftAuctionInfoSheetContent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.gift != rhs.gift {
return false
}
return true
}
final class State: ComponentState {
private let context: AccountContext
private let animateOut: ActionSlot<Action<()>>
private let getController: () -> ViewController?
init(
context: AccountContext,
animateOut: ActionSlot<Action<()>>,
getController: @escaping () -> ViewController?
) {
self.context = context
self.animateOut = animateOut
self.getController = getController
super.init()
}
func dismiss(animated: Bool) {
guard let controller = self.getController() as? GiftAuctionInfoScreen else {
return
}
if animated {
self.animateOut.invoke(Action { [weak controller] _ in
controller?.dismiss(completion: nil)
})
} else {
controller.dismiss(animated: false)
}
}
}
func makeState() -> State {
return State(context: self.context, animateOut: self.animateOut, getController: self.getController)
}
static var body: Body {
let closeButton = Child(GlassBarButtonComponent.self)
let animation = Child(GiftCompositionComponent.self)
let title = Child(BalancedTextComponent.self)
let text = Child(BalancedTextComponent.self)
let list = Child(List<Empty>.self)
let button = Child(ButtonComponent.self)
let giftCompositionExternalState = GiftCompositionComponent.ExternalState()
return { context in
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
let component = context.component
let state = context.state
let controller = environment.controller
let theme = environment.theme
let strings = environment.strings
let _ = strings
let sideInset: CGFloat = 30.0 + environment.safeInsets.left
let textSideInset: CGFloat = 30.0 + environment.safeInsets.left
let titleFont = Font.semibold(20.0)
let textFont = Font.regular(15.0)
let textColor = theme.actionSheet.primaryTextColor
let secondaryTextColor = theme.actionSheet.secondaryTextColor
let linkColor = theme.actionSheet.controlAccentColor
let spacing: CGFloat = 16.0
var contentSize = CGSize(width: context.availableSize.width, height: 30.0)
var animationFile: TelegramMediaFile?
switch component.gift {
case let .generic(gift):
animationFile = gift.file
default:
animationFile = nil
}
let headerHeight: CGFloat = 210.0
let headerSubject: GiftCompositionComponent.Subject?
if let animationFile {
headerSubject = .generic(animationFile)
} else {
headerSubject = nil
}
if let headerSubject {
let animation = animation.update(
component: GiftCompositionComponent(
context: component.context,
theme: theme,
subject: headerSubject,
animationOffset: nil,
animationScale: nil,
displayAnimationStars: false,
externalState: giftCompositionExternalState,
requestUpdate: { [weak state] _ in
state?.updated()
}
),
availableSize: CGSize(width: context.availableSize.width, height: headerHeight),
transition: context.transition
)
context.add(animation
.position(CGPoint(x: context.availableSize.width / 2.0, y: headerHeight / 2.0))
)
}
contentSize.height += headerHeight - 78.0
let title = title.update(
component: BalancedTextComponent(
text: .plain(NSAttributedString(string: "Auction", font: titleFont, textColor: textColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.1
),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
transition: .immediate
)
context.add(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + title.size.height / 2.0))
)
contentSize.height += title.size.height
contentSize.height += spacing - 14.0
let text = text.update(
component: BalancedTextComponent(
text: .plain(NSAttributedString(string: "Join the battle for exclusive gifts.", font: textFont, textColor: secondaryTextColor)),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2
),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
transition: .immediate
)
context.add(text
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + text.size.height / 2.0))
)
contentSize.height += text.size.height
contentSize.height += spacing + 7.0
//TODO:localize
var items: [AnyComponentWithIdentity<Empty>] = []
items.append(
AnyComponentWithIdentity(
id: "top",
component: AnyComponent(ParagraphComponent(
title: "Top 50 Bidders",
titleColor: textColor,
text: "50 gifts are dropped at varying intervals to the top 50 bidders by bid amount.",
textColor: secondaryTextColor,
accentColor: linkColor,
iconName: "Premium/Auction/Drop",
iconColor: linkColor
))
)
)
items.append(
AnyComponentWithIdentity(
id: "carryover",
component: AnyComponent(ParagraphComponent(
title: "Bid Carryover",
titleColor: textColor,
text: "If your bid leaves the top 50, it will automatically join the next drop.",
textColor: secondaryTextColor,
accentColor: linkColor,
iconName: "Premium/Auction/NextDrop",
iconColor: linkColor
))
)
)
items.append(
AnyComponentWithIdentity(
id: "missed",
component: AnyComponent(ParagraphComponent(
title: "Missed Bidders",
titleColor: textColor,
text: "If your bid doesn't win after the final drop, your Stars will be fully refunded.",
textColor: secondaryTextColor,
accentColor: linkColor,
iconName: "Premium/Auction/Refund",
iconColor: linkColor
))
)
)
let list = list.update(
component: List(items),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 10000.0),
transition: context.transition
)
context.add(list
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + list.size.height / 2.0))
)
contentSize.height += list.size.height
contentSize.height += spacing + 8.0
let closeButton = closeButton.update(
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { [weak state] _ in
guard let state else {
return
}
state.dismiss(animated: true)
}
),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
var buttonTitle: [AnyComponentWithIdentity<Empty>] = []
let playButtonAnimation = ActionSlot<Void>()
buttonTitle.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(LottieComponent(
content: LottieComponent.AppBundleContent(name: "anim_ok"),
color: theme.list.itemCheckColors.foregroundColor,
startingPosition: .begin,
size: CGSize(width: 28.0, height: 28.0),
playOnce: playButtonAnimation
))))
buttonTitle.append(AnyComponentWithIdentity(id: 1, component: AnyComponent(ButtonTextContentComponent(
text: "Understood",
badge: 0,
textColor: theme.list.itemCheckColors.foregroundColor,
badgeBackground: theme.list.itemCheckColors.foregroundColor,
badgeForeground: theme.list.itemCheckColors.fillColor
))))
let button = button.update(
component: ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: theme.list.itemCheckColors.fillColor,
foreground: theme.list.itemCheckColors.foregroundColor,
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9),
cornerRadius: 10.0,
),
content: AnyComponentWithIdentity(
id: AnyHashable(0),
component: AnyComponent(HStack(buttonTitle, spacing: 2.0))
),
isEnabled: true,
displaysProgress: false,
action: { [weak state] in
guard let state else {
return
}
state.dismiss(animated: true)
if let controller = controller() as? GiftAuctionInfoScreen {
controller.completion?()
}
}
),
availableSize: CGSize(width: context.availableSize.width - 30.0 * 2.0, height: 52.0),
transition: .immediate
)
context.add(button
.position(CGPoint(x: context.availableSize.width / 2.0, y: contentSize.height + button.size.height / 2.0))
)
contentSize.height += button.size.height
contentSize.height += 30.0
return contentSize
}
}
}
final class GiftAuctionInfoSheetComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let gift: StarGift
init(
context: AccountContext,
gift: StarGift
) {
self.context = context
self.gift = gift
}
static func ==(lhs: GiftAuctionInfoSheetComponent, rhs: GiftAuctionInfoSheetComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.gift != rhs.gift {
return false
}
return true
}
static var body: Body {
let sheet = Child(SheetComponent<EnvironmentType>.self)
let animateOut = StoredActionSlot(Action<Void>.self)
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
return { context in
let environment = context.environment[EnvironmentType.self]
let controller = environment.controller
let sheet = sheet.update(
component: SheetComponent<EnvironmentType>(
content: AnyComponent<EnvironmentType>(GiftAuctionInfoSheetContent(
context: context.component.context,
gift: context.component.gift,
animateOut: animateOut,
getController: controller
)),
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: true,
clipsContent: true,
autoAnimateOut: false,
externalState: sheetExternalState,
animateOut: animateOut,
onPan: {
},
willDismiss: {
}
),
environment: {
environment
SheetComponentEnvironment(
isDisplaying: environment.value.isVisible,
isCentered: environment.metrics.widthClass == .regular,
hasInputHeight: !environment.inputHeight.isZero,
regularMetricsSize: CGSize(width: 430.0, height: 900.0),
dismiss: { animated in
if animated {
if let controller = controller() as? GiftAuctionInfoScreen {
animateOut.invoke(Action { _ in
controller.dismiss(completion: nil)
})
}
} else {
if let controller = controller() as? GiftAuctionInfoScreen {
controller.dismiss(completion: nil)
}
}
}
)
},
availableSize: context.availableSize,
transition: context.transition
)
context.add(sheet
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
)
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
var sideInset: CGFloat = 0.0
var bottomInset: CGFloat = max(environment.safeInsets.bottom, sheetExternalState.contentHeight)
if case .regular = environment.metrics.widthClass {
sideInset = floor((context.availableSize.width - 430.0) / 2.0) - 12.0
bottomInset = (context.availableSize.height - sheetExternalState.contentHeight) / 2.0 + sheetExternalState.contentHeight
}
let layout = ContainerViewLayout(
size: context.availableSize,
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
additionalInsets: .zero,
statusBarHeight: environment.statusBarHeight,
inputHeight: nil,
inputHeightIsInteractivellyChanging: false,
inVoiceOver: false
)
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
}
return context.availableSize
}
}
}
public final class GiftAuctionInfoScreen: ViewControllerComponentContainer {
private let context: AccountContext
private let gift: StarGift
fileprivate let completion: (() -> Void)?
public init(
context: AccountContext,
gift: StarGift,
completion: (() -> Void)?
) {
self.context = context
self.gift = gift
self.completion = completion
super.init(
context: context,
component: GiftAuctionInfoSheetComponent(
context: context,
gift: gift
),
navigationBarAppearance: .none,
statusBarStyle: .ignore,
theme: .default
)
self.navigationPresentation = .flatModal
self.automaticallyControlPresentationContextLayout = false
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
}
public override func viewDidLoad() {
super.viewDidLoad()
self.view.disablesInteractiveModalDismiss = true
}
public override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
public func dismissAnimated() {
if let view = self.node.hostView.findTaggedView(tag: SheetComponent<ViewControllerComponentContainer.Environment>.View.Tag()) as? SheetComponent<ViewControllerComponentContainer.Environment>.View {
view.dismissAnimated()
}
}
}
private final class ParagraphComponent: CombinedComponent {
let title: String
let titleColor: UIColor
let text: String
let textColor: UIColor
let accentColor: UIColor
let iconName: String
let iconColor: UIColor
let action: () -> Void
public init(
title: String,
titleColor: UIColor,
text: String,
textColor: UIColor,
accentColor: UIColor,
iconName: String,
iconColor: UIColor,
action: @escaping () -> Void = {}
) {
self.title = title
self.titleColor = titleColor
self.text = text
self.textColor = textColor
self.accentColor = accentColor
self.iconName = iconName
self.iconColor = iconColor
self.action = action
}
static func ==(lhs: ParagraphComponent, rhs: ParagraphComponent) -> Bool {
if lhs.title != rhs.title {
return false
}
if lhs.titleColor != rhs.titleColor {
return false
}
if lhs.text != rhs.text {
return false
}
if lhs.textColor != rhs.textColor {
return false
}
if lhs.accentColor != rhs.accentColor {
return false
}
if lhs.iconName != rhs.iconName {
return false
}
if lhs.iconColor != rhs.iconColor {
return false
}
return true
}
static var body: Body {
let title = Child(MultilineTextComponent.self)
let text = Child(MultilineTextComponent.self)
let icon = Child(BundleIconComponent.self)
return { context in
let component = context.component
let leftInset: CGFloat = 32.0
let rightInset: CGFloat = 24.0
let textSideInset: CGFloat = leftInset + 8.0
let spacing: CGFloat = 5.0
let textTopInset: CGFloat = 9.0
let title = title.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: component.title,
font: Font.semibold(15.0),
textColor: component.titleColor,
paragraphAlignment: .natural
)),
horizontalAlignment: .center,
maximumNumberOfLines: 1
),
availableSize: CGSize(width: context.availableSize.width - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude),
transition: .immediate
)
let textFont = Font.regular(15.0)
let boldTextFont = Font.semibold(15.0)
let textColor = component.textColor
let accentColor = component.accentColor
let markdownAttributes = MarkdownAttributes(
body: MarkdownAttributeSet(font: textFont, textColor: textColor),
bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor),
link: MarkdownAttributeSet(font: textFont, textColor: accentColor),
linkAttribute: { contents in
return (TelegramTextAttributes.URL, contents)
}
)
let text = text.update(
component: MultilineTextComponent(
text: .markdown(text: component.text, attributes: markdownAttributes),
horizontalAlignment: .natural,
maximumNumberOfLines: 0,
lineSpacing: 0.2,
highlightColor: accentColor.withAlphaComponent(0.1),
highlightAction: { attributes in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
} else {
return nil
}
},
tapAction: { _, _ in
component.action()
}
),
availableSize: CGSize(width: context.availableSize.width - leftInset - rightInset, height: context.availableSize.height),
transition: .immediate
)
let icon = icon.update(
component: BundleIconComponent(
name: component.iconName,
tintColor: component.iconColor
),
availableSize: CGSize(width: context.availableSize.width, height: context.availableSize.height),
transition: .immediate
)
context.add(title
.position(CGPoint(x: textSideInset + title.size.width / 2.0, y: textTopInset + title.size.height / 2.0))
)
context.add(text
.position(CGPoint(x: textSideInset + text.size.width / 2.0, y: textTopInset + title.size.height + spacing + text.size.height / 2.0))
)
context.add(icon
.position(CGPoint(x: 15.0, y: textTopInset + 18.0))
)
return CGSize(width: context.availableSize.width, height: textTopInset + title.size.height + text.size.height + 20.0)
}
}
}

View file

@ -14,23 +14,17 @@ import SheetComponent
import MultilineTextComponent
import MultilineTextWithEntitiesComponent
import BundleIconComponent
import ButtonComponent
import Markdown
import BalancedTextComponent
import AvatarNode
import TextFormat
import TelegramStringFormatting
import StarsAvatarComponent
import EmojiTextAttachmentView
import EmojiStatusComponent
import UndoUI
import PlainButtonComponent
import TooltipUI
import GiftAnimationComponent
import LottieComponent
import ContextUI
import TelegramNotices
import GiftItemComponent
import GlassBarButtonComponent
private final class GiftValueSheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -179,7 +173,7 @@ private final class GiftValueSheetContent: CombinedComponent {
}
static var body: Body {
let buttons = Child(ButtonsComponent.self)
let closeButton = Child(GlassBarButtonComponent.self)
let animation = Child(GiftCompositionComponent.self)
let titleBackground = Child(RoundedRectangle.self)
@ -231,25 +225,7 @@ private final class GiftValueSheetContent: CombinedComponent {
genericGift = gift
}
}
let buttons = buttons.update(
component: ButtonsComponent(
theme: theme,
isOverlay: false,
showMoreButton: false,
closePressed: { [weak state] in
guard let state else {
return
}
state.dismiss(animated: true)
},
morePressed: { _, _ in
}
),
availableSize: CGSize(width: 30.0, height: 30.0),
transition: context.transition
)
var originY: CGFloat = 0.0
let headerHeight: CGFloat = 210.0
@ -655,8 +631,30 @@ private final class GiftValueSheetContent: CombinedComponent {
originY += 12.0
}
context.add(buttons
.position(CGPoint(x: context.availableSize.width - environment.safeInsets.left - 16.0 - buttons.size.width / 2.0, y: 28.0))
let closeButton = closeButton.update(
component: GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
)
)),
action: { [weak state] _ in
guard let state else {
return
}
state.dismiss(animated: true)
}
),
availableSize: CGSize(width: 40.0, height: 40.0),
transition: .immediate
)
context.add(closeButton
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
)
let effectiveBottomInset: CGFloat = environment.metrics.isTablet ? 0.0 : environment.safeInsets.bottom
@ -714,6 +712,7 @@ final class GiftValueSheetComponent: CombinedComponent {
animateOut: animateOut,
getController: controller
)),
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
followContentSizeChanges: true,
clipsContent: true,
@ -849,17 +848,11 @@ final class GiftValueScreen: ViewControllerComponentContainer {
if let controller = controller as? TooltipScreen {
controller.dismiss(inPlace: false)
}
if let controller = controller as? UndoOverlayController {
controller.dismiss()
}
})
self.forEachController({ controller in
if let controller = controller as? TooltipScreen {
controller.dismiss(inPlace: false)
}
if let controller = controller as? UndoOverlayController {
controller.dismiss()
}
return true
})
}

View file

@ -368,6 +368,7 @@ private final class GiftViewSheetContent: CombinedComponent {
deinit {
self.disposable?.dispose()
self.upgradePreviewDisposable.dispose()
self.upgradePreviewTimer?.invalidate()
self.upgradeFormDisposable?.dispose()
self.upgradeDisposable?.dispose()
self.buyFormDisposable?.dispose()
@ -4555,7 +4556,7 @@ private final class GiftViewSheetContent: CombinedComponent {
buttonAnimatedTitleItems.append(
AnimatedTextComponent.Item(
id: AnyHashable(buttonAnimatedTitleItems.count),
content: .icon("Item List/PremiumIcon", offset: CGPoint(x: 1.0, y: 2.0 + UIScreenPixel))
content: .icon("Item List/PremiumIcon", tint: true, offset: CGPoint(x: 1.0, y: 2.0 + UIScreenPixel))
)
)
@ -4607,7 +4608,6 @@ private final class GiftViewSheetContent: CombinedComponent {
} else {
buttonTitleItems.append(AnyComponentWithIdentity(id: "static_label", component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))))
}
let minutes = Int(upgradeTimeout / 60)
let seconds = Int(upgradeTimeout % 60)

View file

@ -203,12 +203,12 @@ public final class ReorderGestureRecognizer: UIGestureRecognizer {
}
public func generateReorderingBackgroundImage(backgroundColor: UIColor) -> UIImage? {
return generateImage(CGSize(width: 64.0, height: 64.0), contextGenerator: { size, context in
return generateImage(CGSize(width: 84.0, height: 84.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
context.addPath(UIBezierPath(roundedRect: CGRect(x: 10, y: 10, width: 44, height: 44), cornerRadius: 10).cgPath)
context.setShadow(offset: CGSize(width: 0.0, height: 0.0), blur: 24.0, color: UIColor(white: 0.0, alpha: 0.35).cgColor)
context.addPath(UIBezierPath(roundedRect: CGRect(x: 16, y: 16, width: 52, height: 52), cornerRadius: 26).cgPath)
context.setShadow(offset: CGSize(width: 0.0, height: 0.0), blur: 36.0, color: UIColor(white: 0.0, alpha: 0.2).cgColor)
context.setFillColor(backgroundColor.cgColor)
context.fillPath()
})?.stretchableImage(withLeftCapWidth: 32, topCapHeight: 32)
})?.stretchableImage(withLeftCapWidth: 42, topCapHeight: 42)
}

View file

@ -95,13 +95,16 @@ public final class ListItemSliderSelectorComponent: Component {
public let theme: PresentationTheme
public let content: Content
public let preferNative: Bool
public init(
theme: PresentationTheme,
content: Content
content: Content,
preferNative: Bool = false
) {
self.theme = theme
self.content = content
self.preferNative = preferNative
}
public static func ==(lhs: ListItemSliderSelectorComponent, rhs: ListItemSliderSelectorComponent) -> Bool {
@ -111,6 +114,9 @@ public final class ListItemSliderSelectorComponent: Component {
if lhs.content != rhs.content {
return false
}
if lhs.preferNative != rhs.preferNative {
return false
}
return true
}
@ -347,6 +353,7 @@ public final class ListItemSliderSelectorComponent: Component {
discrete.selectedIndexUpdated(value)
})
),
useNative: component.preferNative,
trackBackgroundColor: component.theme.list.controlSecondaryColor,
trackForegroundColor: component.theme.list.itemAccentColor,
minTrackForegroundColor: component.theme.list.itemAccentColor.mixedWith(component.theme.list.itemBlocksBackgroundColor, alpha: 0.6)
@ -368,6 +375,7 @@ public final class ListItemSliderSelectorComponent: Component {
continuous.valueUpdated(value)
})
),
useNative: component.preferNative,
trackBackgroundColor: component.theme.list.controlSecondaryColor,
trackForegroundColor: component.theme.list.itemAccentColor,
minTrackForegroundColor: component.theme.list.itemAccentColor.mixedWith(component.theme.list.itemBlocksBackgroundColor, alpha: 0.6)

View file

@ -33,7 +33,9 @@ public final class ListTextFieldItemComponent: Component {
public let placeholder: String
public let autocapitalizationType: UITextAutocapitalizationType
public let autocorrectionType: UITextAutocorrectionType
public let returnKeyType: UIReturnKeyType
public let updated: ((String) -> Void)?
public let onReturn: (() -> Void)?
public let tag: AnyObject?
public init(
@ -44,7 +46,9 @@ public final class ListTextFieldItemComponent: Component {
placeholder: String,
autocapitalizationType: UITextAutocapitalizationType = .sentences,
autocorrectionType: UITextAutocorrectionType = .default,
returnKeyType: UIReturnKeyType = .default,
updated: ((String) -> Void)?,
onReturn: (() -> Void)? = nil,
tag: AnyObject? = nil
) {
self.style = style
@ -54,7 +58,9 @@ public final class ListTextFieldItemComponent: Component {
self.placeholder = placeholder
self.autocapitalizationType = autocapitalizationType
self.autocorrectionType = autocorrectionType
self.returnKeyType = returnKeyType
self.updated = updated
self.onReturn = onReturn
self.tag = tag
}
@ -80,6 +86,9 @@ public final class ListTextFieldItemComponent: Component {
if lhs.autocorrectionType != rhs.autocorrectionType {
return false
}
if lhs.returnKeyType != rhs.returnKeyType {
return false
}
if (lhs.updated == nil) != (rhs.updated == nil) {
return false
}
@ -125,6 +134,7 @@ public final class ListTextFieldItemComponent: Component {
}
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.component?.onReturn?()
return true
}
@ -159,6 +169,14 @@ public final class ListTextFieldItemComponent: Component {
self.textField.becomeFirstResponder()
}
public func textFieldDidBeginEditing(_ textField: UITextField) {
self.clearButton.view?.isHidden = false
}
public func textFieldDidEndEditing(_ textField: UITextField) {
self.clearButton.view?.isHidden = true
}
func update(component: ListTextFieldItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
@ -187,6 +205,9 @@ public final class ListTextFieldItemComponent: Component {
if self.textField.autocorrectionType != component.autocorrectionType {
self.textField.autocorrectionType = component.autocorrectionType
}
if self.textField.returnKeyType != component.returnKeyType {
self.textField.returnKeyType = component.returnKeyType
}
let themeUpdated = component.theme !== previousComponent?.theme
@ -253,7 +274,7 @@ public final class ListTextFieldItemComponent: Component {
self.addSubview(clearButtonView)
}
transition.setFrame(view: clearButtonView, frame: CGRect(origin: CGPoint(x: availableSize.width - 0.0 - clearButtonSize.width, y: floor((contentHeight - clearButtonSize.height) * 0.5)), size: clearButtonSize))
clearButtonView.isHidden = self.currentText.isEmpty
clearButtonView.isHidden = self.currentText.isEmpty || !self.textField.isFirstResponder
}
self.separatorInset = 16.0

View file

@ -58,6 +58,5 @@ fragment float4 bt709ToRGBFragmentShader(RasterizerData in [[stage_in]],
float4 pixel = BT709Decode(Y, Cb, Cr);
pixel = sRGBGammaDecode(pixel);
//pixel.rgb = pow(pixel.rgb, 1.0 / 2.2);
return pixel;
}

View file

@ -58,8 +58,8 @@ private func rectangleMaskImage(size: CGSize) -> CIImage {
return CIImage(cgImage: image!)
}
final class MediaEditorComposer {
enum Input {
public final class MediaEditorComposer {
public enum Input {
case texture(MTLTexture, CMTime, Bool, CGRect?, CGFloat, CGPoint)
case videoBuffer(VideoPixelBuffer, CGRect?, CGFloat, CGPoint)
case ciImage(CIImage, CMTime)
@ -105,8 +105,8 @@ final class MediaEditorComposer {
private var maskImage: CIImage?
init(
postbox: Postbox,
public init(
postbox: Postbox?,
values: MediaEditorValues,
dimensions: CGSize,
outputDimensions: CGSize,
@ -137,8 +137,10 @@ final class MediaEditorComposer {
}
var entities: [MediaEditorComposerEntity] = []
for entity in values.entities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(postbox: postbox, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
if let postbox {
for entity in values.entities {
entities.append(contentsOf: composerEntitiesForDrawingEntity(postbox: postbox, textScale: textScale, entity: entity.entity, colorSpace: colorSpace))
}
}
self.entities = entities
@ -161,7 +163,7 @@ final class MediaEditorComposer {
}
var previousAdditionalInput: [Int: Input] = [:]
func process(main: Input, additional: [Input?], timestamp: CMTime, pool: CVPixelBufferPool?, completion: @escaping (CVPixelBuffer?) -> Void) {
public func process(main: Input, additional: [Input?], timestamp: CMTime, pool: CVPixelBufferPool?, completion: @escaping (CVPixelBuffer?) -> Void) {
guard let pool, let ciContext = self.ciContext else {
completion(nil)
return
@ -254,7 +256,9 @@ public func makeEditorImageComposition(context: CIContext, postbox: Postbox, inp
return
}
}
completion(nil)
Queue.mainQueue().async {
completion(nil)
}
})
}

View file

@ -5,12 +5,12 @@ import MetalKit
import Photos
import SwiftSignalKit
final class VideoPixelBuffer {
public final class VideoPixelBuffer {
let pixelBuffer: CVPixelBuffer
let rotation: TextureRotation
let timestamp: CMTime
init(
public init(
pixelBuffer: CVPixelBuffer,
rotation: TextureRotation,
timestamp: CMTime

View file

@ -9,7 +9,7 @@ struct VertexData {
let localPos: simd_float2
}
enum TextureRotation: Int {
public enum TextureRotation: Int {
case rotate0Degrees
case rotate0DegreesMirrored
case rotate90Degrees

View file

@ -250,7 +250,6 @@ private class MessagePriceItemNode: ListViewItemNode {
self.addSubnode(self.leftTextNode)
self.addSubnode(self.rightTextNode)
self.addSubnode(self.centerTextButtonNode)
self.centerTextButtonNode.view.addSubview(self.centerTextButtonBackground)
self.centerTextButtonNode.addSubnode(self.centerLeftTextNode)
self.centerTextButtonNode.addSubnode(self.centerRightTextNode)
self.addSubnode(self.lockIconNode)
@ -285,6 +284,8 @@ private class MessagePriceItemNode: ListViewItemNode {
self.view.addSubview(sliderView)
sliderView.addTarget(self, action: #selector(self.sliderValueChanged), for: .valueChanged)
self.sliderView = sliderView
self.centerTextButtonNode.view.insertSubview(self.centerTextButtonBackground, at: 0)
}
@objc private func centerTextButtonPressed() {

View file

@ -7890,7 +7890,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
guard let controller = self.controller, !controller.presentAccountFrozenInfoIfNeeded() else {
return
}
self.controller?.push(CreateExternalMediaStreamScreen(context: self.context, peerId: self.peerId, credentialsPromise: credentialsPromise, mode: .create))
self.controller?.push(CreateExternalMediaStreamScreen(context: self.context, peerId: self.peerId, credentialsPromise: credentialsPromise, mode: .create(liveStream: false)))
}
private func createAndJoinGroupCall(peerId: PeerId, joinAsPeerId: PeerId?) {

View file

@ -29,6 +29,7 @@ public final class SearchInputPanelComponent: Component {
public let theme: PresentationTheme
public let strings: PresentationStrings
public let metrics: LayoutMetrics
public let safeInsets: UIEdgeInsets
public let placeholder: String?
public let resetText: ResetText?
public let updated: ((String) -> Void)
@ -38,6 +39,7 @@ public final class SearchInputPanelComponent: Component {
theme: PresentationTheme,
strings: PresentationStrings,
metrics: LayoutMetrics,
safeInsets: UIEdgeInsets,
placeholder: String? = nil,
resetText: ResetText? = nil,
updated: @escaping ((String) -> Void),
@ -46,6 +48,7 @@ public final class SearchInputPanelComponent: Component {
self.theme = theme
self.strings = strings
self.metrics = metrics
self.safeInsets = safeInsets
self.placeholder = placeholder
self.resetText = resetText
self.updated = updated
@ -62,6 +65,9 @@ public final class SearchInputPanelComponent: Component {
if lhs.metrics != rhs.metrics {
return false
}
if lhs.safeInsets != rhs.safeInsets {
return false
}
if lhs.placeholder != rhs.placeholder {
return false
}
@ -189,7 +195,7 @@ public final class SearchInputPanelComponent: Component {
let backgroundColor = component.theme.list.plainBackgroundColor.withMultipliedAlpha(0.75)
var edgeInsets = UIEdgeInsets(top: 10.0, left: 11.0, bottom: 10.0, right: 11.0)
var edgeInsets = UIEdgeInsets(top: 10.0, left: 11.0 + component.safeInsets.left, bottom: 10.0, right: 11.0 + component.safeInsets.right)
if case .regular = component.metrics.widthClass {
edgeInsets.bottom += 18.0
}

View file

@ -25,7 +25,6 @@ swift_library(
"//submodules/AppBundle",
"//submodules/TelegramStringFormatting",
"//submodules/PresentationDataUtils",
"//submodules/Components/SolidRoundedButtonComponent",
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/PlainButtonComponent",
"//submodules/TelegramUI/Components/AnimatedCounterComponent",
@ -42,11 +41,16 @@ swift_library(
"//submodules/UndoUI",
"//submodules/TemporaryCachedPeerDataManager",
"//submodules/CountrySelectionUI",
"//submodules/TelegramUI/Components/ListSectionComponent",
"//submodules/TelegramUI/Components/ListActionItemComponent",
"//submodules/TelegramUI/Components/ListItemSliderSelectorComponent",
"//submodules/ContextUI",
"//submodules/PromptUI",
"//submodules/DirectMediaImageCache",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/EdgeEffect",
"//submodules/TextFormat",
"//submodules/PeerInfoUI/CreateExternalMediaStreamScreen",
],
visibility = [
"//visibility:public",

View file

@ -173,7 +173,7 @@ final class CategoryListItemComponent: Component {
let contextInset: CGFloat = 0.0
let height: CGFloat = 56.0
let height: CGFloat = 64.0
let verticalInset: CGFloat = 0.0
var leftInset: CGFloat = 62.0
let rightInset: CGFloat = contextInset * 2.0 + 8.0
@ -264,7 +264,7 @@ final class CategoryListItemComponent: Component {
containerSize: CGSize(width: availableSize.width - leftInset - rightInset, height: 100.0)
)
let titleSpacing: CGFloat = 1.0
let titleSpacing: CGFloat = 3.0
var centralContentHeight: CGFloat = titleSize.height
if !labelData.0.isEmpty {
centralContentHeight += titleSpacing + labelSize.height

View file

@ -14,7 +14,6 @@ import MultilineTextComponent
import PresentationDataUtils
import ButtonComponent
import TokenListTextField
import AvatarNode
import LocalizedPeerData
import PeerListItemComponent
import LottieComponent
@ -2770,15 +2769,6 @@ final class ShareWithPeersScreenComponent: Component {
let navigationLeftButtonSize = self.navigationLeftButton.update(
transition: transition,
// component: AnyComponent(Button(
// content: AnyComponent(Text(text: environment.strings.Common_Cancel, font: Font.regular(17.0), color: environment.theme.rootController.navigationBar.accentTextColor)),
// action: { [weak self] in
// guard let self else {
// return
// }
// self.saveAndDismiss()
// }
// ).minSize(CGSize(width: navigationHeight, height: navigationHeight))),
component: AnyComponent(GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: environment.theme.rootController.navigationBar.glassBarButtonBackgroundColor,
@ -2811,7 +2801,12 @@ final class ShareWithPeersScreenComponent: Component {
var subtitle: String?
switch component.stateContext.subject {
case .peers:
title = environment.strings.Story_Privacy_PostStoryAs
//TODO:localize
if component.stateContext.liveStream {
title = "Start Live As"
} else {
title = environment.strings.Story_Privacy_PostStoryAs
}
case let .stories(editing, count):
if editing {
title = environment.strings.Story_Privacy_EditStory
@ -2913,7 +2908,7 @@ final class ShareWithPeersScreenComponent: Component {
inset = 1000.0
} else if case let .stories(editing, _) = component.stateContext.subject {
if editing {
inset = 351.0
inset = 383.0
inset += 10.0 + environment.safeInsets.bottom + 50.0 + footersTotalHeight
} else {
if !hasCategories {

View file

@ -55,6 +55,7 @@ public extension ShareWithPeersScreen {
var stateValue: State?
public let subject: Subject
public let liveStream: Bool
public let editing: Bool
public private(set) var initialPeerIds: Set<EnginePeer.Id> = Set()
let blockedPeersContext: BlockedPeersContext?
@ -74,6 +75,7 @@ public extension ShareWithPeersScreen {
public init(
context: AccountContext,
subject: Subject = .chats(blocked: false),
liveStream: Bool = false,
editing: Bool = false,
initialSelectedPeers: [EngineStoryPrivacy.Base: [EnginePeer.Id]] = [:],
initialPeerIds: Set<EnginePeer.Id> = Set(),
@ -82,6 +84,7 @@ public extension ShareWithPeersScreen {
blockedPeersContext: BlockedPeersContext? = nil
) {
self.subject = subject
self.liveStream = liveStream
self.editing = editing
self.initialPeerIds = initialPeerIds
self.blockedPeersContext = blockedPeersContext
@ -721,7 +724,7 @@ final class PeersListStoredState: Codable {
}
}
private func peersListStoredState(engine: TelegramEngine, base: Stories.Item.Privacy.Base) -> Signal<[EnginePeer.Id], NoError> {
func peersListStoredState(engine: TelegramEngine, base: Stories.Item.Privacy.Base) -> Signal<[EnginePeer.Id], NoError> {
let key = EngineDataBuffer(length: 4)
key.setInt32(0, value: base.rawValue)

View file

@ -17,6 +17,7 @@ final class StoryAuthorInfoComponent: Component {
let context: AccountContext
let strings: PresentationStrings
let isEmbeddedInCamera: Bool
let peer: EnginePeer?
let forwardInfo: EngineStoryItem.ForwardInfo?
let author: EnginePeer?
@ -26,9 +27,10 @@ final class StoryAuthorInfoComponent: Component {
let isLiveStream: Bool
let customSubtitle: String?
init(context: AccountContext, strings: PresentationStrings, peer: EnginePeer?, forwardInfo: EngineStoryItem.ForwardInfo?, author: EnginePeer?, timestamp: Int32, counters: Counters?, isEdited: Bool, isLiveStream: Bool, customSubtitle: String?) {
init(context: AccountContext, strings: PresentationStrings, isEmbeddedInCamera: Bool, peer: EnginePeer?, forwardInfo: EngineStoryItem.ForwardInfo?, author: EnginePeer?, timestamp: Int32, counters: Counters?, isEdited: Bool, isLiveStream: Bool, customSubtitle: String?) {
self.context = context
self.strings = strings
self.isEmbeddedInCamera = isEmbeddedInCamera
self.peer = peer
self.forwardInfo = forwardInfo
self.author = author
@ -45,6 +47,9 @@ final class StoryAuthorInfoComponent: Component {
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.isEmbeddedInCamera != rhs.isEmbeddedInCamera {
return false
}
if lhs.peer != rhs.peer {
return false
@ -105,7 +110,7 @@ final class StoryAuthorInfoComponent: Component {
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
let title: String
if component.peer?.id == component.context.account.peerId {
if component.peer?.id == component.context.account.peerId, !component.isEmbeddedInCamera {
title = component.strings.Story_HeaderYourStory
} else {
if let _ = component.counters {

View file

@ -920,7 +920,8 @@ final class StoryItemContentComponent: Component {
mediaStreamTransition.setFrame(view: liveChatView, frame: liveChatFrame)
}
if !component.isEmbeddedInCamera {
if case .rtc = liveStream.kind, component.isEmbeddedInCamera {
} else {
let _ = mediaStream.update(
transition: mediaStreamTransition,
component: AnyComponent(MediaStreamVideoComponent(
@ -1113,7 +1114,8 @@ final class StoryItemContentComponent: Component {
self.unsupportedButton = nil
unsupportedButton.view?.removeFromSuperview()
}
if !component.isEmbeddedInCamera {
if component.isEmbeddedInCamera, case let .liveStream(liveStream) = messageMedia, case .rtc = liveStream.kind {
} else {
self.backgroundColor = .black
}
default:
@ -1205,7 +1207,8 @@ final class StoryItemContentComponent: Component {
#endif
}
if !component.isEmbeddedInCamera && (!self.contentLoaded || component.isVideoBuffering) {
if component.isEmbeddedInCamera, case let .liveStream(liveStream) = messageMedia, case .rtc = liveStream.kind {
} else if !self.contentLoaded || component.isVideoBuffering {
let loadingEffectView: StoryItemLoadingEffectView
if let current = self.loadingEffectView {
loadingEffectView = current

View file

@ -4218,6 +4218,7 @@ public final class StoryItemSetContainerComponent: Component {
let centerInfoComponent = AnyComponent(StoryAuthorInfoComponent(
context: component.context,
strings: component.strings,
isEmbeddedInCamera: component.isEmbeddedInCamera,
peer: component.slice.effectivePeer,
forwardInfo: component.slice.item.storyItem.forwardInfo,
author: component.slice.item.storyItem.author,

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "infoheader.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "drop.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "nextdrop.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "starsrefund.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -527,7 +527,9 @@ extension ChatControllerImpl {
if options.contains(.deleteLocally) {
var localOptionText = self.presentationData.strings.Conversation_DeleteMessagesForMe
if self.chatLocation.peerId == self.context.account.peerId {
if case .peer(self.context.account.peerId) = self.chatLocation, messages.values.allSatisfy({ message in message?._asMessage().effectivelyIncoming(self.context.account.peerId) ?? false }) {
if case .scheduledMessages = self.presentationInterfaceState.subject {
localOptionText = messageIds.count > 1 ? self.presentationData.strings.ScheduledMessages_Reminder_DeleteMany : self.presentationData.strings.ScheduledMessages_Reminder_Delete
} else if case .peer(self.context.account.peerId) = self.chatLocation, messages.values.allSatisfy({ message in message?._asMessage().effectivelyIncoming(self.context.account.peerId) ?? false }) {
localOptionText = self.presentationData.strings.Chat_ConfirmationRemoveFromSavedMessages
} else {
localOptionText = self.presentationData.strings.Chat_ConfirmationDeleteFromSavedMessages

Some files were not shown because too many files have changed in this diff Show more