Merge commit 'a91658373baee67ebcef073a68b21b87787ca6eb'

This commit is contained in:
Isaac 2025-09-26 00:14:28 +08:00
commit 73b67e9a4e
11 changed files with 199 additions and 130 deletions

View File

@ -217,9 +217,9 @@ public enum DeviceMetrics: CaseIterable, Equatable {
case .iPhone14Pro, .iPhone14ProMax: case .iPhone14Pro, .iPhone14ProMax:
return 55.0 return 55.0
case .iPhone16Pro, .iPhone16ProMax: case .iPhone16Pro, .iPhone16ProMax:
return 55.0 return 62.0
case .iPhoneAir: case .iPhoneAir:
return 55.0 return 62.0
case let .unknown(_, _, _, screenCornerRadius): case let .unknown(_, _, _, screenCornerRadius):
return screenCornerRadius return screenCornerRadius
default: default:

View File

@ -965,7 +965,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) } dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
dict[-963180333] = { return Api.SponsoredPeer.parse_sponsoredPeer($0) } dict[-963180333] = { return Api.SponsoredPeer.parse_sponsoredPeer($0) }
dict[-2136190013] = { return Api.StarGift.parse_starGift($0) } dict[-2136190013] = { return Api.StarGift.parse_starGift($0) }
dict[973640632] = { return Api.StarGift.parse_starGiftUnique($0) } dict[-1329630181] = { return Api.StarGift.parse_starGiftUnique($0) }
dict[-650279524] = { return Api.StarGiftAttribute.parse_starGiftAttributeBackdrop($0) } dict[-650279524] = { return Api.StarGiftAttribute.parse_starGiftAttributeBackdrop($0) }
dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) } dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) }
dict[-524291476] = { return Api.StarGiftAttribute.parse_starGiftAttributeOriginalDetails($0) } dict[-524291476] = { return Api.StarGiftAttribute.parse_starGiftAttributeOriginalDetails($0) }

View File

@ -289,7 +289,7 @@ public extension Api {
public extension Api { public extension Api {
enum StarGift: TypeConstructorDescription { enum StarGift: TypeConstructorDescription {
case starGift(flags: Int32, id: Int64, sticker: Api.Document, stars: Int64, availabilityRemains: Int32?, availabilityTotal: Int32?, availabilityResale: Int64?, convertStars: Int64, firstSaleDate: Int32?, lastSaleDate: Int32?, upgradeStars: Int64?, resellMinStars: Int64?, title: String?, releasedBy: Api.Peer?, perUserTotal: Int32?, perUserRemains: Int32?, lockedUntilDate: Int32?) case starGift(flags: Int32, id: Int64, sticker: Api.Document, stars: Int64, availabilityRemains: Int32?, availabilityTotal: Int32?, availabilityResale: Int64?, convertStars: Int64, firstSaleDate: Int32?, lastSaleDate: Int32?, upgradeStars: Int64?, resellMinStars: Int64?, title: String?, releasedBy: Api.Peer?, perUserTotal: Int32?, perUserRemains: Int32?, lockedUntilDate: Int32?)
case starGiftUnique(flags: Int32, id: Int64, giftId: Int64, title: String, slug: String, num: Int32, ownerId: Api.Peer?, ownerName: String?, ownerAddress: String?, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32, giftAddress: String?, resellAmount: [Api.StarsAmount]?, releasedBy: Api.Peer?, valueAmount: Int64?, valueCurrency: String?, themePeer: Api.Peer?, peerColor: Api.PeerColor?) case starGiftUnique(flags: Int32, id: Int64, giftId: Int64, title: String, slug: String, num: Int32, ownerId: Api.Peer?, ownerName: String?, ownerAddress: String?, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32, giftAddress: String?, resellAmount: [Api.StarsAmount]?, releasedBy: Api.Peer?, valueAmount: Int64?, valueCurrency: String?, themePeer: Api.Peer?, peerColor: Api.PeerColor?, hostId: Api.Peer?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
@ -315,9 +315,9 @@ public extension Api {
if Int(flags) & Int(1 << 8) != 0 {serializeInt32(perUserRemains!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 8) != 0 {serializeInt32(perUserRemains!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 9) != 0 {serializeInt32(lockedUntilDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 9) != 0 {serializeInt32(lockedUntilDate!, buffer: buffer, boxed: false)}
break break
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer, let peerColor): case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer, let peerColor, let hostId):
if boxed { if boxed {
buffer.appendInt32(973640632) buffer.appendInt32(-1329630181)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(id, buffer: buffer, boxed: false) serializeInt64(id, buffer: buffer, boxed: false)
@ -346,6 +346,7 @@ public extension Api {
if Int(flags) & Int(1 << 8) != 0 {serializeString(valueCurrency!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 8) != 0 {serializeString(valueCurrency!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 10) != 0 {themePeer!.serialize(buffer, true)} if Int(flags) & Int(1 << 10) != 0 {themePeer!.serialize(buffer, true)}
if Int(flags) & Int(1 << 11) != 0 {peerColor!.serialize(buffer, true)} if Int(flags) & Int(1 << 11) != 0 {peerColor!.serialize(buffer, true)}
if Int(flags) & Int(1 << 12) != 0 {hostId!.serialize(buffer, true)}
break break
} }
} }
@ -354,8 +355,8 @@ public extension Api {
switch self { switch self {
case .starGift(let flags, let id, let sticker, let stars, let availabilityRemains, let availabilityTotal, let availabilityResale, let convertStars, let firstSaleDate, let lastSaleDate, let upgradeStars, let resellMinStars, let title, let releasedBy, let perUserTotal, let perUserRemains, let lockedUntilDate): case .starGift(let flags, let id, let sticker, let stars, let availabilityRemains, let availabilityTotal, let availabilityResale, let convertStars, let firstSaleDate, let lastSaleDate, let upgradeStars, let resellMinStars, let title, let releasedBy, let perUserTotal, let perUserRemains, let lockedUntilDate):
return ("starGift", [("flags", flags as Any), ("id", id as Any), ("sticker", sticker as Any), ("stars", stars as Any), ("availabilityRemains", availabilityRemains as Any), ("availabilityTotal", availabilityTotal as Any), ("availabilityResale", availabilityResale as Any), ("convertStars", convertStars as Any), ("firstSaleDate", firstSaleDate as Any), ("lastSaleDate", lastSaleDate as Any), ("upgradeStars", upgradeStars as Any), ("resellMinStars", resellMinStars as Any), ("title", title as Any), ("releasedBy", releasedBy as Any), ("perUserTotal", perUserTotal as Any), ("perUserRemains", perUserRemains as Any), ("lockedUntilDate", lockedUntilDate as Any)]) return ("starGift", [("flags", flags as Any), ("id", id as Any), ("sticker", sticker as Any), ("stars", stars as Any), ("availabilityRemains", availabilityRemains as Any), ("availabilityTotal", availabilityTotal as Any), ("availabilityResale", availabilityResale as Any), ("convertStars", convertStars as Any), ("firstSaleDate", firstSaleDate as Any), ("lastSaleDate", lastSaleDate as Any), ("upgradeStars", upgradeStars as Any), ("resellMinStars", resellMinStars as Any), ("title", title as Any), ("releasedBy", releasedBy as Any), ("perUserTotal", perUserTotal as Any), ("perUserRemains", perUserRemains as Any), ("lockedUntilDate", lockedUntilDate as Any)])
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer, let peerColor): case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer, let peerColor, let hostId):
return ("starGiftUnique", [("flags", flags as Any), ("id", id as Any), ("giftId", giftId as Any), ("title", title as Any), ("slug", slug as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("ownerName", ownerName as Any), ("ownerAddress", ownerAddress as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any), ("giftAddress", giftAddress as Any), ("resellAmount", resellAmount as Any), ("releasedBy", releasedBy as Any), ("valueAmount", valueAmount as Any), ("valueCurrency", valueCurrency as Any), ("themePeer", themePeer as Any), ("peerColor", peerColor as Any)]) return ("starGiftUnique", [("flags", flags as Any), ("id", id as Any), ("giftId", giftId as Any), ("title", title as Any), ("slug", slug as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("ownerName", ownerName as Any), ("ownerAddress", ownerAddress as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any), ("giftAddress", giftAddress as Any), ("resellAmount", resellAmount as Any), ("releasedBy", releasedBy as Any), ("valueAmount", valueAmount as Any), ("valueCurrency", valueCurrency as Any), ("themePeer", themePeer as Any), ("peerColor", peerColor as Any), ("hostId", hostId as Any)])
} }
} }
@ -473,6 +474,10 @@ public extension Api {
if Int(_1!) & Int(1 << 11) != 0 {if let signature = reader.readInt32() { if Int(_1!) & Int(1 << 11) != 0 {if let signature = reader.readInt32() {
_19 = Api.parse(reader, signature: signature) as? Api.PeerColor _19 = Api.parse(reader, signature: signature) as? Api.PeerColor
} } } }
var _20: Api.Peer?
if Int(_1!) & Int(1 << 12) != 0 {if let signature = reader.readInt32() {
_20 = Api.parse(reader, signature: signature) as? Api.Peer
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
@ -492,8 +497,9 @@ public extension Api {
let _c17 = (Int(_1!) & Int(1 << 8) == 0) || _17 != nil let _c17 = (Int(_1!) & Int(1 << 8) == 0) || _17 != nil
let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil
let _c19 = (Int(_1!) & Int(1 << 11) == 0) || _19 != nil let _c19 = (Int(_1!) & Int(1 << 11) == 0) || _19 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 { let _c20 = (Int(_1!) & Int(1 << 12) == 0) || _20 != nil
return Api.StarGift.starGiftUnique(flags: _1!, id: _2!, giftId: _3!, title: _4!, slug: _5!, num: _6!, ownerId: _7, ownerName: _8, ownerAddress: _9, attributes: _10!, availabilityIssued: _11!, availabilityTotal: _12!, giftAddress: _13, resellAmount: _14, releasedBy: _15, valueAmount: _16, valueCurrency: _17, themePeer: _18, peerColor: _19) if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 {
return Api.StarGift.starGiftUnique(flags: _1!, id: _2!, giftId: _3!, title: _4!, slug: _5!, num: _6!, ownerId: _7, ownerName: _8, ownerAddress: _9, attributes: _10!, availabilityIssued: _11!, availabilityTotal: _12!, giftAddress: _13, resellAmount: _14, releasedBy: _15, valueAmount: _16, valueCurrency: _17, themePeer: _18, peerColor: _19, hostId: _20)
} }
else { else {
return nil return nil

View File

@ -520,9 +520,10 @@ final class VideoChatMicButtonComponent: Component {
var titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) * 0.5), y: size.height + 16.0), size: titleSize) var titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) * 0.5), y: size.height + 16.0), size: titleSize)
if component.isCompact { if component.isCompact {
titleFrame.origin.y -= 11.0 titleFrame.origin.y -= 11.0
} } else {
if subtitleText != nil { if subtitleText != nil {
titleFrame.origin.y -= 5.0 titleFrame.origin.y -= 5.0
}
} }
if let titleView = self.title.view { if let titleView = self.title.view {
if titleView.superview == nil { if titleView.superview == nil {

View File

@ -2034,7 +2034,7 @@ final class VideoChatParticipantsComponent: Component {
} else { } else {
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1) let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
let value: CGFloat = 1.0 - Display.bezierPoint(0.42, 0.0, 0.58, 1.0, step) let value: CGFloat = 1.0 - Display.bezierPoint(0.42, 0.0, 0.58, 1.0, step)
return UIColor(white: 0.0, alpha: baseGradientAlpha * value).multipliedWith(.red) return UIColor(white: 0.0, alpha: baseGradientAlpha * value)
} }
} }
let locations = (0 ..< numSteps).map { i -> CGFloat in let locations = (0 ..< numSteps).map { i -> CGFloat in

View File

@ -2206,7 +2206,7 @@ final class VideoChatScreenComponent: Component {
let landscapeControlsWidth: CGFloat = 104.0 let landscapeControlsWidth: CGFloat = 104.0
var landscapeControlsOffsetX: CGFloat = 0.0 var landscapeControlsOffsetX: CGFloat = 0.0
let landscapeControlsSpacing: CGFloat = 30.0 let landscapeControlsSpacing: CGFloat = 20.0
var leftInset: CGFloat = max(environment.safeInsets.left, 16.0) var leftInset: CGFloat = max(environment.safeInsets.left, 16.0)
@ -2554,11 +2554,58 @@ final class VideoChatScreenComponent: Component {
self.encryptionKeyBackground = nil self.encryptionKeyBackground = nil
} }
let videoButtonContent: VideoChatActionButtonComponent.Content?
let videoControlButtonContent: VideoChatActionButtonComponent.Content
var buttonAudio: VideoChatActionButtonComponent.Content.Audio = .speaker
var buttonIsEnabled = false
if let (availableOutputs, maybeCurrentOutput) = self.audioOutputState, let currentOutput = maybeCurrentOutput {
buttonIsEnabled = availableOutputs.count > 1
switch currentOutput {
case .builtin:
buttonAudio = .builtin
case .speaker:
buttonAudio = .speaker
case .headphones:
buttonAudio = .headphones
case let .port(port):
var type: VideoChatActionButtonComponent.Content.BluetoothType = .generic
let portName = port.name.lowercased()
if portName.contains("airpods max") {
type = .airpodsMax
} else if portName.contains("airpods pro") {
type = .airpodsPro
} else if portName.contains("airpods") {
type = .airpods
}
buttonAudio = .bluetooth(type)
}
if availableOutputs.count <= 1 {
buttonAudio = .none
}
}
if let callState = self.callState, let muteState = callState.muteState, !muteState.canUnmute {
videoButtonContent = nil
videoControlButtonContent = .audio(audio: buttonAudio, isEnabled: buttonIsEnabled)
} else {
let isVideoActive = self.callState?.isMyVideoActive ?? false
videoButtonContent = .video(isActive: isVideoActive)
if isVideoActive {
videoControlButtonContent = .rotateCamera
} else {
videoControlButtonContent = .audio(audio: buttonAudio, isEnabled: buttonIsEnabled)
}
}
let actionButtonDiameter: CGFloat = 56.0 let actionButtonDiameter: CGFloat = 56.0
let expandedMicrophoneButtonDiameter: CGFloat = actionButtonDiameter let expandedMicrophoneButtonDiameter: CGFloat = actionButtonDiameter
let collapsedMicrophoneButtonDiameter: CGFloat = actionButtonDiameter // 116.0 let collapsedMicrophoneButtonDiameter: CGFloat = actionButtonDiameter // 116.0
let buttonsWidth: CGFloat = actionButtonDiameter * 5.0 let buttonsCount = videoButtonContent == nil ? 4 : 5
let buttonsWidth: CGFloat = actionButtonDiameter * CGFloat(buttonsCount)
let remainingButtonsSpace: CGFloat let remainingButtonsSpace: CGFloat
if isTwoColumnLayout { if isTwoColumnLayout {
remainingButtonsSpace = mainColumnWidth - buttonsWidth remainingButtonsSpace = mainColumnWidth - buttonsWidth
@ -2566,7 +2613,7 @@ final class VideoChatScreenComponent: Component {
remainingButtonsSpace = availableSize.width - 16.0 * 2.0 - buttonsWidth remainingButtonsSpace = availableSize.width - 16.0 * 2.0 - buttonsWidth
} }
let actionMicrophoneButtonSpacing = min(25.0, floor(remainingButtonsSpace * 0.25)) let actionMicrophoneButtonSpacing = min(33.0, floor(remainingButtonsSpace / CGFloat(buttonsCount - 1)))
var collapsedMicrophoneButtonFrame: CGRect = CGRect(origin: CGPoint(x: floor((availableSize.width - collapsedMicrophoneButtonDiameter) * 0.5), y: availableSize.height - 48.0 - environment.safeInsets.bottom - collapsedMicrophoneButtonDiameter), size: CGSize(width: collapsedMicrophoneButtonDiameter, height: collapsedMicrophoneButtonDiameter)) var collapsedMicrophoneButtonFrame: CGRect = CGRect(origin: CGPoint(x: floor((availableSize.width - collapsedMicrophoneButtonDiameter) * 0.5), y: availableSize.height - 48.0 - environment.safeInsets.bottom - collapsedMicrophoneButtonDiameter), size: CGSize(width: collapsedMicrophoneButtonDiameter, height: collapsedMicrophoneButtonDiameter))
if self.isAnimatedOutFromPrivateCall { if self.isAnimatedOutFromPrivateCall {
@ -2607,7 +2654,7 @@ final class VideoChatScreenComponent: Component {
} }
} }
let microphoneButtonFrame: CGRect var microphoneButtonFrame: CGRect
if areButtonsCollapsed { if areButtonsCollapsed {
microphoneButtonFrame = expandedMicrophoneButtonFrame microphoneButtonFrame = expandedMicrophoneButtonFrame
} else { } else {
@ -2631,25 +2678,40 @@ final class VideoChatScreenComponent: Component {
} else { } else {
expandedParticipantsClippingY = expandedMicrophoneButtonFrame.minY - 24.0 expandedParticipantsClippingY = expandedMicrophoneButtonFrame.minY - 24.0
} }
let actionButtonSize = CGSize(width: actionButtonDiameter, height: actionButtonDiameter) let actionButtonSize = CGSize(width: actionButtonDiameter, height: actionButtonDiameter)
var firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - (actionButtonDiameter + actionMicrophoneButtonSpacing) * 2.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) var firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - (actionButtonDiameter + actionMicrophoneButtonSpacing) * 2.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
var secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + actionMicrophoneButtonSpacing + actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) var secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + actionMicrophoneButtonSpacing + actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
var fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + 2.0 * actionMicrophoneButtonSpacing + actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) var fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + 2.0 * actionMicrophoneButtonSpacing + actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
var thirdActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) var thirdActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize)
if buttonsOnTheSide { if buttonsCount == 4 {
secondActionButtonFrame.origin.x = microphoneButtonFrame.minX if buttonsOnTheSide {
secondActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter firstActionButtonFrame.origin.x = microphoneButtonFrame.minX
secondActionButtonFrame.origin.x = microphoneButtonFrame.minX
thirdActionButtonFrame.origin.x = microphoneButtonFrame.minX
fourthActionButtonFrame.origin.x = microphoneButtonFrame.minX
microphoneButtonFrame.origin.y = availableSize.height * 0.5 - landscapeControlsSpacing * 0.5 - actionButtonDiameter
firstActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
thirdActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing
fourthActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing + actionButtonDiameter + landscapeControlsSpacing
} else {
microphoneButtonFrame.origin.x = availableSize.width * 0.5 - actionMicrophoneButtonSpacing * 0.5 - actionButtonDiameter
firstActionButtonFrame.origin.x = microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter
thirdActionButtonFrame.origin.x = microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing
fourthActionButtonFrame.origin.x = microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing + actionButtonDiameter + actionMicrophoneButtonSpacing
}
} else if buttonsOnTheSide {
firstActionButtonFrame.origin.x = microphoneButtonFrame.minX firstActionButtonFrame.origin.x = microphoneButtonFrame.minX
firstActionButtonFrame.origin.y = secondActionButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter secondActionButtonFrame.origin.x = microphoneButtonFrame.minX
thirdActionButtonFrame.origin.x = microphoneButtonFrame.minX thirdActionButtonFrame.origin.x = microphoneButtonFrame.minX
thirdActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing
fourthActionButtonFrame.origin.x = microphoneButtonFrame.minX fourthActionButtonFrame.origin.x = microphoneButtonFrame.minX
secondActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
firstActionButtonFrame.origin.y = secondActionButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter
thirdActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing
fourthActionButtonFrame.origin.y = thirdActionButtonFrame.maxY + landscapeControlsSpacing fourthActionButtonFrame.origin.y = thirdActionButtonFrame.maxY + landscapeControlsSpacing
} }
@ -3065,84 +3127,7 @@ final class VideoChatScreenComponent: Component {
transition.setBounds(view: microphoneButtonView, bounds: CGRect(origin: CGPoint(), size: microphoneButtonFrame.size)) transition.setBounds(view: microphoneButtonView, bounds: CGRect(origin: CGPoint(), size: microphoneButtonFrame.size))
} }
let videoButtonContent: VideoChatActionButtonComponent.Content
let videoControlButtonContent: VideoChatActionButtonComponent.Content
var buttonAudio: VideoChatActionButtonComponent.Content.Audio = .speaker
var buttonIsEnabled = false
if let (availableOutputs, maybeCurrentOutput) = self.audioOutputState, let currentOutput = maybeCurrentOutput {
buttonIsEnabled = availableOutputs.count > 1
switch currentOutput {
case .builtin:
buttonAudio = .builtin
case .speaker:
buttonAudio = .speaker
case .headphones:
buttonAudio = .headphones
case let .port(port):
var type: VideoChatActionButtonComponent.Content.BluetoothType = .generic
let portName = port.name.lowercased()
if portName.contains("airpods max") {
type = .airpodsMax
} else if portName.contains("airpods pro") {
type = .airpodsPro
} else if portName.contains("airpods") {
type = .airpods
}
buttonAudio = .bluetooth(type)
}
if availableOutputs.count <= 1 {
buttonAudio = .none
}
}
if let callState = self.callState, let muteState = callState.muteState, !muteState.canUnmute {
videoButtonContent = .audio(audio: buttonAudio, isEnabled: buttonIsEnabled)
videoControlButtonContent = .audio(audio: buttonAudio, isEnabled: buttonIsEnabled)
} else {
let isVideoActive = self.callState?.isMyVideoActive ?? false
videoButtonContent = .video(isActive: isVideoActive)
if isVideoActive {
videoControlButtonContent = .rotateCamera
} else {
videoControlButtonContent = .audio(audio: buttonAudio, isEnabled: buttonIsEnabled)
}
}
let _ = self.videoButton.update(
transition: transition,
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(VideoChatActionButtonComponent(
strings: environment.strings,
content: videoButtonContent,
microphoneState: actionButtonMicrophoneState,
isCollapsed: areButtonsActuallyCollapsed || buttonsOnTheSide
)),
effectAlignment: .center,
action: { [weak self] in
guard let self else {
return
}
if let callState = self.callState, let muteState = callState.muteState, !muteState.canUnmute {
self.onAudioRoutePressed()
} else {
self.onCameraPressed()
}
},
animateAlpha: false
)),
environment: {},
containerSize: CGSize(width: actionButtonDiameter, height: actionButtonDiameter)
)
if let videoButtonView = self.videoButton.view {
if videoButtonView.superview == nil {
self.containerView.addSubview(videoButtonView)
}
transition.setPosition(view: videoButtonView, position: secondActionButtonFrame.center)
transition.setBounds(view: videoButtonView, bounds: CGRect(origin: CGPoint(), size: secondActionButtonFrame.size))
}
let _ = self.speakerButton.update( let _ = self.speakerButton.update(
transition: transition, transition: transition,
component: AnyComponent(PlainButtonComponent( component: AnyComponent(PlainButtonComponent(
@ -3178,6 +3163,47 @@ final class VideoChatScreenComponent: Component {
transition.setBounds(view: speakerButtonView, bounds: CGRect(origin: CGPoint(), size: firstActionButtonFrame.size)) transition.setBounds(view: speakerButtonView, bounds: CGRect(origin: CGPoint(), size: firstActionButtonFrame.size))
} }
if let videoButtonContent {
let _ = self.videoButton.update(
transition: transition,
component: AnyComponent(PlainButtonComponent(
content: AnyComponent(VideoChatActionButtonComponent(
strings: environment.strings,
content: videoButtonContent,
microphoneState: actionButtonMicrophoneState,
isCollapsed: areButtonsActuallyCollapsed || buttonsOnTheSide
)),
effectAlignment: .center,
action: { [weak self] in
guard let self else {
return
}
if let callState = self.callState, let muteState = callState.muteState, !muteState.canUnmute {
self.onAudioRoutePressed()
} else {
self.onCameraPressed()
}
},
animateAlpha: false
)),
environment: {},
containerSize: CGSize(width: actionButtonDiameter, height: actionButtonDiameter)
)
if let videoButtonView = self.videoButton.view {
if videoButtonView.superview == nil {
self.containerView.addSubview(videoButtonView)
}
transition.setPosition(view: videoButtonView, position: secondActionButtonFrame.center)
transition.setBounds(view: videoButtonView, bounds: CGRect(origin: CGPoint(), size: secondActionButtonFrame.size))
}
} else if let videoButtonView = self.videoButton.view {
let transition = ComponentTransition(animation: .curve(duration: 0.25, curve: .easeInOut))
transition.animateScale(view: videoButtonView, from: 1.0, to: 0.01)
transition.animateAlpha(view: videoButtonView, from: 1.0, to: 0.0, completion: { _ in
videoButtonView.removeFromSuperview()
})
}
let _ = self.messageButton.update( let _ = self.messageButton.update(
transition: transition, transition: transition,
component: AnyComponent(PlainButtonComponent( component: AnyComponent(PlainButtonComponent(
@ -3239,7 +3265,7 @@ final class VideoChatScreenComponent: Component {
var inputPanelBottomInset: CGFloat = 0.0 var inputPanelBottomInset: CGFloat = 0.0
var inputPanelSize: CGSize = .zero var inputPanelSize: CGSize = .zero
if self.inputPanelIsActive { if self.inputPanelIsActive {
let inputPanelAvailableWidth = availableSize.width let inputPanelAvailableWidth = availableSize.width - environment.safeInsets.left - environment.safeInsets.right
var inputPanelAvailableHeight = 103.0 var inputPanelAvailableHeight = 103.0
let keyboardWasHidden = self.inputPanelExternalState.isKeyboardHidden let keyboardWasHidden = self.inputPanelExternalState.isKeyboardHidden
@ -3462,7 +3488,11 @@ final class VideoChatScreenComponent: Component {
inputPanelBottomInset = inputHeight - environment.safeInsets.bottom inputPanelBottomInset = inputHeight - environment.safeInsets.bottom
} else { } else {
if self.inputPanelExternalState.isEditing { if self.inputPanelExternalState.isEditing {
inputPanelBottomInset = availableSize.height - microphoneButtonFrame.minY if buttonsOnTheSide {
inputPanelBottomInset = 16.0
} else {
inputPanelBottomInset = availableSize.height - microphoneButtonFrame.minY
}
} else { } else {
inputPanelBottomInset = -inputPanelSize.height - environment.safeInsets.bottom inputPanelBottomInset = -inputPanelSize.height - environment.safeInsets.bottom
} }
@ -3758,7 +3788,8 @@ final class VideoChatScreenComponent: Component {
} }
} }
let messagesBottomInset: CGFloat = max(inputPanelBottomInset + inputPanelSize.height + 31.0, availableSize.height - microphoneButtonFrame.minY + 16.0) + reactionsInset let normalMessagesBottomInset: CGFloat = buttonsOnTheSide ? 16.0 : availableSize.height - microphoneButtonFrame.minY + 16.0
let messagesBottomInset: CGFloat = max(inputPanelBottomInset + inputPanelSize.height + 31.0, normalMessagesBottomInset) + reactionsInset
let messagesListSize = self.messagesList.update( let messagesListSize = self.messagesList.update(
transition: transition, transition: transition,
component: AnyComponent(MessageListComponent( component: AnyComponent(MessageListComponent(
@ -3768,9 +3799,9 @@ final class VideoChatScreenComponent: Component {
sendActionTransition: sendActionTransition sendActionTransition: sendActionTransition
)), )),
environment: {}, environment: {},
containerSize: CGSize(width: availableSize.width, height: availableSize.height - messagesBottomInset) containerSize: CGSize(width: availableSize.width - environment.safeInsets.left - environment.safeInsets.right, height: availableSize.height - messagesBottomInset)
) )
let messagesListFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - messagesListSize.height - messagesBottomInset), size: messagesListSize) let messagesListFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - messagesListSize.width) / 2.0), y: availableSize.height - messagesListSize.height - messagesBottomInset), size: messagesListSize)
if let messagesListView = self.messagesList.view { if let messagesListView = self.messagesList.view {
if messagesListView.superview == nil { if messagesListView.superview == nil {
messagesListView.isUserInteractionEnabled = false messagesListView.isUserInteractionEnabled = false

View File

@ -362,7 +362,8 @@ func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Ne
valueCurrency: nil, valueCurrency: nil,
flags: [], flags: [],
themePeerId: nil, themePeerId: nil,
peerColor: nil peerColor: nil,
hostPeerId: nil
) )
if let entry = CodableEntry(RecentStarGiftItem(gift)) { if let entry = CodableEntry(RecentStarGiftItem(gift)) {
items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry)) items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry))

View File

@ -322,6 +322,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
case flags case flags
case themePeerId case themePeerId
case peerColor case peerColor
case hostPeerId
} }
public struct Flags: OptionSet { public struct Flags: OptionSet {
@ -610,8 +611,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
public let flags: Flags public let flags: Flags
public let themePeerId: EnginePeer.Id? public let themePeerId: EnginePeer.Id?
public let peerColor: PeerCollectibleColor? public let peerColor: PeerCollectibleColor?
public let hostPeerId: EnginePeer.Id?
public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?, flags: Flags, themePeerId: EnginePeer.Id?, peerColor: PeerCollectibleColor?) { public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?, flags: Flags, themePeerId: EnginePeer.Id?, peerColor: PeerCollectibleColor?, hostPeerId: EnginePeer.Id?) {
self.id = id self.id = id
self.giftId = giftId self.giftId = giftId
self.title = title self.title = title
@ -629,6 +631,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
self.flags = flags self.flags = flags
self.themePeerId = themePeerId self.themePeerId = themePeerId
self.peerColor = peerColor self.peerColor = peerColor
self.hostPeerId = hostPeerId
} }
public init(from decoder: Decoder) throws { public init(from decoder: Decoder) throws {
@ -664,6 +667,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
self.flags = try container.decodeIfPresent(Int32.self, forKey: .flags).flatMap { Flags(rawValue: $0) } ?? [] self.flags = try container.decodeIfPresent(Int32.self, forKey: .flags).flatMap { Flags(rawValue: $0) } ?? []
self.themePeerId = try container.decodeIfPresent(Int64.self, forKey: .themePeerId).flatMap { EnginePeer.Id($0) } self.themePeerId = try container.decodeIfPresent(Int64.self, forKey: .themePeerId).flatMap { EnginePeer.Id($0) }
self.peerColor = try container.decodeIfPresent(PeerCollectibleColor.self, forKey: .peerColor) self.peerColor = try container.decodeIfPresent(PeerCollectibleColor.self, forKey: .peerColor)
self.hostPeerId = try container.decodeIfPresent(Int64.self, forKey: .hostPeerId).flatMap { EnginePeer.Id($0) }
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -698,6 +702,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
self.flags = decoder.decodeOptionalInt32ForKey(CodingKeys.flags.rawValue).flatMap { Flags(rawValue: $0) } ?? [] self.flags = decoder.decodeOptionalInt32ForKey(CodingKeys.flags.rawValue).flatMap { Flags(rawValue: $0) } ?? []
self.themePeerId = decoder.decodeOptionalInt64ForKey(CodingKeys.themePeerId.rawValue).flatMap { EnginePeer.Id($0) } self.themePeerId = decoder.decodeOptionalInt64ForKey(CodingKeys.themePeerId.rawValue).flatMap { EnginePeer.Id($0) }
self.peerColor = decoder.decodeCodable(PeerCollectibleColor.self, forKey: CodingKeys.peerColor.rawValue) self.peerColor = decoder.decodeCodable(PeerCollectibleColor.self, forKey: CodingKeys.peerColor.rawValue)
self.hostPeerId = decoder.decodeOptionalInt64ForKey(CodingKeys.hostPeerId.rawValue).flatMap { EnginePeer.Id($0) }
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
@ -726,6 +731,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
try container.encode(self.flags.rawValue, forKey: .flags) try container.encode(self.flags.rawValue, forKey: .flags)
try container.encodeIfPresent(self.themePeerId?.toInt64(), forKey: .themePeerId) try container.encodeIfPresent(self.themePeerId?.toInt64(), forKey: .themePeerId)
try container.encodeIfPresent(self.peerColor, forKey: .peerColor) try container.encodeIfPresent(self.peerColor, forKey: .peerColor)
try container.encodeIfPresent(self.hostPeerId?.toInt64(), forKey: .hostPeerId)
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -778,6 +784,11 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
} else { } else {
encoder.encodeNil(forKey: CodingKeys.peerColor.rawValue) encoder.encodeNil(forKey: CodingKeys.peerColor.rawValue)
} }
if let hostPeerId = self.hostPeerId {
encoder.encodeInt64(hostPeerId.toInt64(), forKey: CodingKeys.hostPeerId.rawValue)
} else {
encoder.encodeNil(forKey: CodingKeys.hostPeerId.rawValue)
}
} }
public func withResellAmounts(_ resellAmounts: [CurrencyAmount]?) -> UniqueGift { public func withResellAmounts(_ resellAmounts: [CurrencyAmount]?) -> UniqueGift {
@ -798,7 +809,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
valueCurrency: self.valueCurrency, valueCurrency: self.valueCurrency,
flags: self.flags, flags: self.flags,
themePeerId: self.themePeerId, themePeerId: self.themePeerId,
peerColor: self.peerColor peerColor: self.peerColor,
hostPeerId: self.hostPeerId
) )
} }
@ -820,7 +832,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
valueCurrency: self.valueCurrency, valueCurrency: self.valueCurrency,
flags: self.flags, flags: self.flags,
themePeerId: self.themePeerId, themePeerId: self.themePeerId,
peerColor: self.peerColor peerColor: self.peerColor,
hostPeerId: self.hostPeerId
) )
} }
@ -842,7 +855,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
valueCurrency: self.valueCurrency, valueCurrency: self.valueCurrency,
flags: self.flags, flags: self.flags,
themePeerId: themePeerId, themePeerId: themePeerId,
peerColor: self.peerColor peerColor: self.peerColor,
hostPeerId: self.hostPeerId
) )
} }
@ -864,7 +878,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
valueCurrency: self.valueCurrency, valueCurrency: self.valueCurrency,
flags: self.flags, flags: self.flags,
themePeerId: self.themePeerId, themePeerId: self.themePeerId,
peerColor: self.peerColor peerColor: self.peerColor,
hostPeerId: self.hostPeerId
) )
} }
} }
@ -977,7 +992,7 @@ extension StarGift {
return nil return nil
} }
self = .generic(StarGift.Gift(id: id, title: title, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags, upgradeStars: upgradeStars, releasedBy: releasedBy?.peerId, perUserLimit: perUserLimit, lockedUntilDate: lockedUntilDate)) self = .generic(StarGift.Gift(id: id, title: title, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags, upgradeStars: upgradeStars, releasedBy: releasedBy?.peerId, perUserLimit: perUserLimit, lockedUntilDate: lockedUntilDate))
case let .starGiftUnique(apiFlags, id, giftId, title, slug, num, ownerPeerId, ownerName, ownerAddress, attributes, availabilityIssued, availabilityTotal, giftAddress, resellAmounts, releasedBy, valueAmount, valueCurrency, themePeer, peerColor): case let .starGiftUnique(apiFlags, id, giftId, title, slug, num, ownerPeerId, ownerName, ownerAddress, attributes, availabilityIssued, availabilityTotal, giftAddress, resellAmounts, releasedBy, valueAmount, valueCurrency, themePeer, peerColor, hostPeerId):
let owner: StarGift.UniqueGift.Owner let owner: StarGift.UniqueGift.Owner
if let ownerAddress { if let ownerAddress {
owner = .address(ownerAddress) owner = .address(ownerAddress)
@ -1009,7 +1024,7 @@ extension StarGift {
break break
} }
self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (apiFlags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency, flags: flags, themePeerId: themePeer?.peerId, peerColor: peerCollectibleColor)) self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (apiFlags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency, flags: flags, themePeerId: themePeer?.peerId, peerColor: peerCollectibleColor, hostPeerId: hostPeerId?.peerId))
} }
} }
} }

View File

@ -332,14 +332,6 @@ public extension Peer {
} }
var profileColor: PeerNameColor? { var profileColor: PeerNameColor? {
if let emojiStatus {
switch emojiStatus.content {
case let .starGift(_, _, _, _, _, _, outerColor, _, _):
return PeerNameColor.other(outerColor)
default:
break
}
}
switch self { switch self {
case let user as TelegramUser: case let user as TelegramUser:
return user.profileColor return user.profileColor
@ -402,7 +394,7 @@ public extension Peer {
public extension TelegramPeerUsername { public extension TelegramPeerUsername {
var isActive: Bool { var isActive: Bool {
return self.flags.contains(.isActive) || self.flags.contains(.isEditable) return self.flags.contains(.isActive)
} }
} }

View File

@ -1501,7 +1501,18 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
} }
if let note = cachedData.note, !note.text.isEmpty { if let note = cachedData.note, !note.text.isEmpty {
items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_Notes, rightLabel: presentationData.strings.PeerInfo_NotesInfo, text: note.text, entities: note.entities, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, linkItemAction: bioLinkAction, button: nil, contextAction: noteContextAction, requestLayout: { animated in var entities = note.entities
if !context.isPremium {
entities = entities.filter { entity in
switch entity.type {
case .Url, .TextUrl:
return false
default:
return true
}
}
}
items[currentPeerInfoSection]!.append(PeerInfoScreenLabeledValueItem(id: 0, label: presentationData.strings.PeerInfo_Notes, rightLabel: presentationData.strings.PeerInfo_NotesInfo, text: note.text, entities: entities, textColor: .primary, textBehavior: .multiLine(maxLines: 100, enabledEntities: []), action: nil, linkItemAction: bioLinkAction, button: nil, contextAction: noteContextAction, requestLayout: { animated in
interaction.requestLayout(animated) interaction.requestLayout(animated)
})) }))
} }
@ -4577,7 +4588,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
let noteUpdateSignal: Signal<Never, ContactUpdateError> let noteUpdateSignal: Signal<Never, ContactUpdateError>
if noteUpdated, let note { if noteUpdated, let note {
let entities = generateChatInputTextEntities(note) let entities = generateTextEntities(note.string, enabledTypes: [.mention, .hashtag, .allUrl], currentEntities: generateChatInputTextEntities(note))
noteUpdateSignal = context.engine.contacts.updateContactNote(peerId: peer.id, text: note.string, entities: entities) noteUpdateSignal = context.engine.contacts.updateContactNote(peerId: peer.id, text: note.string, entities: entities)
|> mapError { _ -> ContactUpdateError in |> mapError { _ -> ContactUpdateError in
return .generic return .generic

View File

@ -768,7 +768,8 @@ final class UserAppearanceScreenComponent: Component {
valueCurrency: nil, valueCurrency: nil,
flags: [], flags: [],
themePeerId: nil, themePeerId: nil,
peerColor: nil peerColor: nil,
hostPeerId: nil
) )
signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate) signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate)
} else { } else {
@ -1110,7 +1111,16 @@ final class UserAppearanceScreenComponent: Component {
let updatedSection = Section(rawValue: intValue) ?? .profile let updatedSection = Section(rawValue: intValue) ?? .profile
if self.currentSection != updatedSection { if self.currentSection != updatedSection {
if (updatedSection == .name && self.selectedProfileGift != nil) || (updatedSection == .profile && self.selectedNameGift != nil) { if (updatedSection == .name && self.selectedProfileGift != nil) || (updatedSection == .profile && self.selectedNameGift != nil) {
switch updatedSection {
case .profile:
self.selectedNameGift = nil
self.updatedPeerNameColor = nil
self.updatedPeerNameEmoji = nil
case .name:
self.selectedProfileGift = nil
self.updatedPeerProfileColor = nil
self.updatedPeerProfileEmoji = nil
}
} else { } else {
self.currentSection = updatedSection self.currentSection = updatedSection
self.state?.updated(transition: .easeInOut(duration: 0.3).withUserData(TransitionHint(animateTabChange: true))) self.state?.updated(transition: .easeInOut(duration: 0.3).withUserData(TransitionHint(animateTabChange: true)))
@ -1871,6 +1881,8 @@ public class UserAppearanceScreen: ViewControllerComponentContainer {
self.automaticallyControlPresentationContextLayout = false self.automaticallyControlPresentationContextLayout = false
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.title = "" self.title = ""
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil) self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)