Various fixes

This commit is contained in:
Ilya Laktyushin 2024-12-06 18:32:57 +04:00
parent c016f0dd7e
commit 704156e55f
21 changed files with 148 additions and 76 deletions

View File

@ -13304,6 +13304,8 @@ Sorry for the inconvenience.";
"Chat.VideoProcessingInfo" = "The video will be published once converted and optimized."; "Chat.VideoProcessingInfo" = "The video will be published once converted and optimized.";
"Camera.CollageRetake" = "Retake";
"Camera.CollageDelete" = "Delete";
"Camera.CollageManagementTooltip" = "Tap a tile to delete or reorder it."; "Camera.CollageManagementTooltip" = "Tap a tile to delete or reorder it.";
"Camera.CollageReorderingInfo" = "Hold and drag tiles to reorder them."; "Camera.CollageReorderingInfo" = "Hold and drag tiles to reorder them.";

View File

@ -519,10 +519,13 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
default: default:
break break
} }
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
canManage = true
} else if case let .channel(peer) = peer, case .broadcast = peer.info, peer.hasPermission(.addAdmins) {
canManage = true
} }
if canManage { if canManage {
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
} else { } else {
enabled = false enabled = false
} }
@ -2413,10 +2416,13 @@ public final class ChatListNode: ListView {
default: default:
break break
} }
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
canManage = true
} else if case let .channel(peer) = peer, case .broadcast = peer.info, peer.hasPermission(.addAdmins) {
canManage = true
} }
if canManage { if canManage {
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
} else { } else {
return false return false
} }

View File

@ -605,6 +605,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
var result: [ChatListNodeEntry] = [] var result: [ChatListNodeEntry] = []
var hasContacts = false
if !view.hasEarlier { if !view.hasEarlier {
var existingPeerIds = Set<EnginePeer.Id>() var existingPeerIds = Set<EnginePeer.Id>()
for item in view.items { for item in view.items {
@ -620,8 +621,9 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
peer: contact.peer, peer: contact.peer,
presence: contact.presence presence: contact.presence
))) )))
hasContacts = true
} }
if !contacts.isEmpty { if hasContacts {
result.append(.SectionHeader(presentationData: state.presentationData, displayHide: !view.items.isEmpty)) result.append(.SectionHeader(presentationData: state.presentationData, displayHide: !view.items.isEmpty))
} }
} }

View File

@ -1277,9 +1277,20 @@ public final class ChatPresentationInterfaceState: Equatable {
} }
} }
public func canBypassRestrictions(chatPresentationInterfaceState: ChatPresentationInterfaceState) -> Bool {
guard let boostsToUnrestrict = chatPresentationInterfaceState.boostsToUnrestrict, boostsToUnrestrict > 0 else {
return false
}
if let appliedBoosts = chatPresentationInterfaceState.appliedBoosts, appliedBoosts >= boostsToUnrestrict {
return true
}
return false
}
public func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bool { public func canSendMessagesToChat(_ state: ChatPresentationInterfaceState) -> Bool {
if let peer = state.renderedPeer?.peer { if let peer = state.renderedPeer?.peer {
if canSendMessagesToPeer(peer) { let canBypassRestrictions = canBypassRestrictions(chatPresentationInterfaceState: state)
if canSendMessagesToPeer(peer, ignoreDefault: canBypassRestrictions) {
return true return true
} else { } else {
return false return false

View File

@ -97,7 +97,11 @@ final class NavigationTransitionCoordinator {
case .Push: case .Push:
self.container.addSubnode(topNode) self.container.addSubnode(topNode)
case .Pop: case .Pop:
self.container.insertSubnode(bottomNode, belowSubnode: topNode) if topNode.supernode == self.container {
self.container.insertSubnode(bottomNode, belowSubnode: topNode)
} else {
self.container.addSubnode(topNode)
}
} }
if !self.isFlat { if !self.isFlat {

View File

@ -871,6 +871,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
if !isVideo { if !isVideo {
canEdit = true canEdit = true
isImage = true
} }
} else if let media = media as? TelegramMediaWebpage, case let .Loaded(content) = media.content { } else if let media = media as? TelegramMediaWebpage, case let .Loaded(content) = media.content {
let type = webEmbedType(content: content) let type = webEmbedType(content: content)

View File

@ -908,7 +908,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1577421297] = { return Api.StarsGiftOption.parse_starsGiftOption($0) } dict[1577421297] = { return Api.StarsGiftOption.parse_starsGiftOption($0) }
dict[-1798404822] = { return Api.StarsGiveawayOption.parse_starsGiveawayOption($0) } dict[-1798404822] = { return Api.StarsGiveawayOption.parse_starsGiveawayOption($0) }
dict[1411605001] = { return Api.StarsGiveawayWinnersOption.parse_starsGiveawayWinnersOption($0) } dict[1411605001] = { return Api.StarsGiveawayWinnersOption.parse_starsGiveawayWinnersOption($0) }
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) } dict[-21080943] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
dict[779004698] = { return Api.StarsSubscription.parse_starsSubscription($0) } dict[779004698] = { return Api.StarsSubscription.parse_starsSubscription($0) }
dict[88173912] = { return Api.StarsSubscriptionPricing.parse_starsSubscriptionPricing($0) } dict[88173912] = { return Api.StarsSubscriptionPricing.parse_starsSubscriptionPricing($0) }
dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) } dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) }

View File

@ -904,18 +904,18 @@ public extension Api {
} }
public extension Api { public extension Api {
enum StarsRevenueStatus: TypeConstructorDescription { enum StarsRevenueStatus: TypeConstructorDescription {
case starsRevenueStatus(flags: Int32, currentBalance: Int64, availableBalance: Int64, overallRevenue: Int64, nextWithdrawalAt: Int32?) case starsRevenueStatus(flags: Int32, currentBalance: Api.StarsAmount, availableBalance: Api.StarsAmount, overallRevenue: Api.StarsAmount, nextWithdrawalAt: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .starsRevenueStatus(let flags, let currentBalance, let availableBalance, let overallRevenue, let nextWithdrawalAt): case .starsRevenueStatus(let flags, let currentBalance, let availableBalance, let overallRevenue, let nextWithdrawalAt):
if boxed { if boxed {
buffer.appendInt32(2033461574) buffer.appendInt32(-21080943)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(currentBalance, buffer: buffer, boxed: false) currentBalance.serialize(buffer, true)
serializeInt64(availableBalance, buffer: buffer, boxed: false) availableBalance.serialize(buffer, true)
serializeInt64(overallRevenue, buffer: buffer, boxed: false) overallRevenue.serialize(buffer, true)
if Int(flags) & Int(1 << 1) != 0 {serializeInt32(nextWithdrawalAt!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 1) != 0 {serializeInt32(nextWithdrawalAt!, buffer: buffer, boxed: false)}
break break
} }
@ -931,12 +931,18 @@ public extension Api {
public static func parse_starsRevenueStatus(_ reader: BufferReader) -> StarsRevenueStatus? { public static func parse_starsRevenueStatus(_ reader: BufferReader) -> StarsRevenueStatus? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()
var _2: Int64? var _2: Api.StarsAmount?
_2 = reader.readInt64() if let signature = reader.readInt32() {
var _3: Int64? _2 = Api.parse(reader, signature: signature) as? Api.StarsAmount
_3 = reader.readInt64() }
var _4: Int64? var _3: Api.StarsAmount?
_4 = reader.readInt64() if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.StarsAmount
}
var _4: Api.StarsAmount?
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.StarsAmount
}
var _5: Int32? var _5: Int32?
if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() }
let _c1 = _1 != nil let _c1 = _1 != nil

View File

@ -24,7 +24,7 @@ public enum TelegramChannelPermission {
} }
public extension TelegramChannel { public extension TelegramChannel {
func hasPermission(_ permission: TelegramChannelPermission) -> Bool { func hasPermission(_ permission: TelegramChannelPermission, ignoreDefault: Bool = false) -> Bool {
if self.flags.contains(.isCreator) { if self.flags.contains(.isCreator) {
if case .canBeAnonymous = permission { if case .canBeAnonymous = permission {
if let adminRights = self.adminRights { if let adminRights = self.adminRights {
@ -50,7 +50,7 @@ public extension TelegramChannel {
if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendText) { if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendText) {
return false return false
} }
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendText) { if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendText) && !ignoreDefault {
return false return false
} }
return true return true
@ -69,7 +69,7 @@ public extension TelegramChannel {
if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendPhotos) { if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendPhotos) {
return false return false
} }
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendPhotos) { if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendText) && !ignoreDefault {
return false return false
} }
return true return true
@ -88,7 +88,7 @@ public extension TelegramChannel {
if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendVideos) { if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banSendVideos) {
return false return false
} }
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendVideos) { if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banSendVideos) && !ignoreDefault {
return false return false
} }
return true return true
@ -121,7 +121,7 @@ public extension TelegramChannel {
if let bannedRights = self.bannedRights, bannedRights.flags.intersection(flags) == flags { if let bannedRights = self.bannedRights, bannedRights.flags.intersection(flags) == flags {
return false return false
} }
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.intersection(flags) == flags { if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.intersection(flags) == flags && !ignoreDefault {
return false return false
} }
return true return true

View File

@ -146,7 +146,7 @@ extension StarsRevenueStats.Balances {
init(apiStarsRevenueStatus: Api.StarsRevenueStatus) { init(apiStarsRevenueStatus: Api.StarsRevenueStatus) {
switch apiStarsRevenueStatus { switch apiStarsRevenueStatus {
case let .starsRevenueStatus(flags, currentBalance, availableBalance, overallRevenue, nextWithdrawalAt): case let .starsRevenueStatus(flags, currentBalance, availableBalance, overallRevenue, nextWithdrawalAt):
self.init(currentBalance: StarsAmount(value: currentBalance, nanos: 0), availableBalance: StarsAmount(value: availableBalance, nanos: 0), overallRevenue: StarsAmount(value: overallRevenue, nanos: 0), withdrawEnabled: ((flags & (1 << 0)) != 0), nextWithdrawalTimestamp: nextWithdrawalAt) self.init(currentBalance: StarsAmount(apiAmount: currentBalance), availableBalance: StarsAmount(apiAmount: availableBalance), overallRevenue: StarsAmount(apiAmount: overallRevenue), withdrawEnabled: ((flags & (1 << 0)) != 0), nextWithdrawalTimestamp: nextWithdrawalAt)
} }
} }
} }

View File

@ -6,7 +6,7 @@ import Postbox
private final class LinkHelperClass: NSObject { private final class LinkHelperClass: NSObject {
} }
public func canSendMessagesToPeer(_ peer: Peer) -> Bool { public func canSendMessagesToPeer(_ peer: Peer, ignoreDefault: Bool = false) -> Bool {
if let peer = peer as? TelegramUser, peer.addressName == "replies" { if let peer = peer as? TelegramUser, peer.addressName == "replies" {
return false return false
} else if peer is TelegramUser || peer is TelegramGroup { } else if peer is TelegramUser || peer is TelegramGroup {
@ -14,7 +14,7 @@ public func canSendMessagesToPeer(_ peer: Peer) -> Bool {
} else if let peer = peer as? TelegramSecretChat { } else if let peer = peer as? TelegramSecretChat {
return peer.embeddedState == .active return peer.embeddedState == .active
} else if let peer = peer as? TelegramChannel { } else if let peer = peer as? TelegramChannel {
return peer.hasPermission(.sendSomething) return peer.hasPermission(.sendSomething, ignoreDefault: ignoreDefault)
} else { } else {
return false return false
} }

View File

@ -504,6 +504,10 @@ final class CameraCollageView: UIView, UIGestureRecognizerDelegate {
self.contextAction?(item.uniqueId, self.extractedContainerView, nil) self.contextAction?(item.uniqueId, self.extractedContainerView, nil)
} }
func stopPlayback() {
self.videoPlayer?.pause()
}
func resetPlayback() { func resetPlayback() {
self.videoPlayer?.seek(to: .zero) self.videoPlayer?.seek(to: .zero)
self.videoPlayer?.play() self.videoPlayer?.play()
@ -680,10 +684,10 @@ final class CameraCollageView: UIView, UIGestureRecognizerDelegate {
} else { } else {
delayAppearance = true delayAppearance = true
Queue.mainQueue().after(0.2, {
snapshotView.removeFromSuperview()
})
} }
Queue.mainQueue().after(0.2, {
snapshotView.removeFromSuperview()
})
self.snapshotView = nil self.snapshotView = nil
} }
if let previewLayer = self.previewLayer { if let previewLayer = self.previewLayer {
@ -991,6 +995,12 @@ final class CameraCollageView: UIView, UIGestureRecognizerDelegate {
} }
} }
func stopPlayback() {
for (_, itemView) in self.itemViews {
itemView.stopPlayback()
}
}
func resetPlayback() { func resetPlayback() {
for (_, itemView) in self.itemViews { for (_, itemView) in self.itemViews {
itemView.resetPlayback() itemView.resetPlayback()
@ -1054,7 +1064,7 @@ final class CameraCollageView: UIView, UIGestureRecognizerDelegate {
var itemList: [ContextMenuItem] = [] var itemList: [ContextMenuItem] = []
if self.collage.cameraIndex == nil { if self.collage.cameraIndex == nil {
itemList.append(.action(ContextMenuActionItem(text: "Retake", icon: { theme in itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.Camera_CollageRetake, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Camera"), color: theme.contextMenu.primaryColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Camera"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, f in }, action: { [weak self] _, f in
f(.default) f(.default)
@ -1066,7 +1076,7 @@ final class CameraCollageView: UIView, UIGestureRecognizerDelegate {
if self.itemViews.count > 2 { if self.itemViews.count > 2 {
itemList.append(.separator) itemList.append(.separator)
itemList.append(.action(ContextMenuActionItem(text: "Delete", textColor: .destructive, icon: { theme in itemList.append(.action(ContextMenuActionItem(text: presentationData.strings.Camera_CollageDelete, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
}, action: { [weak self] _, f in }, action: { [weak self] _, f in
f(.dismissWithoutContent) f(.dismissWithoutContent)

View File

@ -2615,13 +2615,9 @@ public class CameraScreenImpl: ViewController, CameraScreen {
view.animateOutToEditor(transition: transition) view.animateOutToEditor(transition: transition)
} }
Queue.mainQueue().after(2.0, { Queue.mainQueue().after(1.5, {
if self.cameraState.isCollageEnabled { if let collageView = self.collageView {
self.collage = nil collageView.stopPlayback()
if let collageView = self.collageView {
collageView.removeFromSuperview()
self.collageView = nil
}
} }
}) })
} }
@ -2679,6 +2675,10 @@ public class CameraScreenImpl: ViewController, CameraScreen {
if !toGallery { if !toGallery {
self.resumeCameraCapture(fromGallery: false) self.resumeCameraCapture(fromGallery: false)
if let collageView = self.collageView {
collageView.resetPlayback()
}
self.cameraIsActive = true self.cameraIsActive = true
self.requestUpdateLayout(transition: .immediate) self.requestUpdateLayout(transition: .immediate)

View File

@ -999,14 +999,22 @@ final class CaptureControlsComponent: Component {
func animateInFromEditor(transition: ComponentTransition) { func animateInFromEditor(transition: ComponentTransition) {
self.animatedOut = false self.animatedOut = false
guard let component = self.component else {
return
}
if let view = self.galleryButtonView.view { if let view = self.galleryButtonView.view {
transition.setScale(view: view, scale: 1.0) transition.setScale(view: view, scale: 1.0)
transition.setAlpha(view: view, alpha: 1.0) if !component.hideControls {
transition.setAlpha(view: view, alpha: 1.0)
}
} }
if let view = self.flipButtonView.view { if let view = self.flipButtonView.view {
transition.setScale(view: view, scale: 1.0) transition.setScale(view: view, scale: 1.0)
transition.setAlpha(view: view, alpha: 1.0) if !component.hideControls {
transition.setAlpha(view: view, alpha: 1.0)
}
} }
if let view = self.shutterButtonView.view { if let view = self.shutterButtonView.view {

View File

@ -432,8 +432,8 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
buttons = [ buttons = [
self.deleteButton, self.deleteButton,
tagButton, tagButton,
self.forwardButton, self.shareButton,
self.shareButton self.forwardButton
] ]
} else { } else {
buttons = [ buttons = [

View File

@ -406,7 +406,7 @@ final class GiftSetupScreenComponent: Component {
purpose: .starGift(peerId: component.peerId, requiredStars: starGift.price), purpose: .starGift(peerId: component.peerId, requiredStars: starGift.price),
completion: { [weak starsContext] stars in completion: { [weak starsContext] stars in
starsContext?.add(balance: StarsAmount(value: stars, nanos: 0)) starsContext?.add(balance: StarsAmount(value: stars, nanos: 0))
Queue.mainQueue().after(0.1) { Queue.mainQueue().after(2.0) {
proceed() proceed()
} }
} }

View File

@ -433,7 +433,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
updateTimeout(nil) updateTimeout(nil)
}))) })))
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(sourceView: sourceView, position: self.currentIsCaptionAbove ? .bottom : .top)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.present(contextController) self.present(contextController)
} }
@ -552,11 +552,14 @@ private final class HeaderContextReferenceContentSource: ContextReferenceContent
return true return true
} }
init(sourceView: UIView) { let position: ContextControllerReferenceViewInfo.ActionsPosition
init(sourceView: UIView, position: ContextControllerReferenceViewInfo.ActionsPosition) {
self.sourceView = sourceView self.sourceView = sourceView
self.position = position
} }
func transitionInfo() -> ContextControllerReferenceViewInfo? { func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds, actionsPosition: .top) return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds, actionsPosition: self.position)
} }
} }

View File

@ -188,7 +188,7 @@ public final class MediaEditor {
private var additionalPlayers: [AVPlayer] = [] private var additionalPlayers: [AVPlayer] = []
private let additionalPlayersPromise = Promise<[AVPlayer]>([]) private let additionalPlayersPromise = Promise<[AVPlayer]>([])
private var additionalPlayerAudioMix: AVMutableAudioMix? private var additionalPlayerAudioMixes: [AVMutableAudioMix] = []
private var audioPlayer: AVPlayer? private var audioPlayer: AVPlayer?
private let audioPlayerPromise = Promise<AVPlayer?>(nil) private let audioPlayerPromise = Promise<AVPlayer?>(nil)
@ -1732,11 +1732,11 @@ public final class MediaEditor {
} }
self.updateValues(mode: .skipRendering) { values in self.updateValues(mode: .skipRendering) { values in
var values = values.withUpdatedCollage(collage) return values.withUpdatedCollage(collage)
if mainVideoIsMuted { }
values = values.withUpdatedVideoVolume(0.0)
} if mainVideoIsMuted {
return values self.setVideoVolume(0.0)
} }
self.setupAdditionalVideoPlayback() self.setupAdditionalVideoPlayback()
@ -1756,7 +1756,7 @@ public final class MediaEditor {
self.additionalPlayers.forEach { $0.pause() } self.additionalPlayers.forEach { $0.pause() }
self.additionalPlayers = [] self.additionalPlayers = []
self.additionalPlayersPromise.set(.single([])) self.additionalPlayersPromise.set(.single([]))
self.additionalPlayerAudioMix = nil self.additionalPlayerAudioMixes = []
if let textureSource = self.renderer.textureSource as? UniversalTextureSource { if let textureSource = self.renderer.textureSource as? UniversalTextureSource {
textureSource.forceUpdates = true textureSource.forceUpdates = true
@ -1837,19 +1837,29 @@ public final class MediaEditor {
} }
var additionalInputs: [UniversalTextureSource.Input] = [] var additionalInputs: [UniversalTextureSource.Input] = []
var additionalPlayers: [AVPlayer] = [] var additionalPlayers: [AVPlayer] = []
var audioMixes: [AVMutableAudioMix] = []
for (input, player, volume) in results { for (input, player, volume) in results {
additionalInputs.append(input) additionalInputs.append(input)
if let player { if let player {
if let volume {
player.volume = Float(volume)
}
additionalPlayers.append(player) additionalPlayers.append(player)
if let asset = player.currentItem?.asset {
let audioMix = AVMutableAudioMix()
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
if let volume {
audioMixInputParameters.setVolume(Float(volume), at: .zero)
}
audioMix.inputParameters = [audioMixInputParameters]
player.currentItem?.audioMix = audioMix
audioMixes.append(audioMix)
}
} }
} }
self.additionalPlayers = additionalPlayers self.additionalPlayers = additionalPlayers
self.additionalPlayersPromise.set(.single(additionalPlayers)) self.additionalPlayersPromise.set(.single(additionalPlayers))
self.additionalPlayerAudioMixes = audioMixes
(self.renderer.textureSource as? UniversalTextureSource)?.setAdditionalInputs(additionalInputs) (self.renderer.textureSource as? UniversalTextureSource)?.setAdditionalInputs(additionalInputs)
@ -1878,7 +1888,7 @@ public final class MediaEditor {
self.additionalPlayers = [player] self.additionalPlayers = [player]
self.additionalPlayersPromise.set(.single([player])) self.additionalPlayersPromise.set(.single([player]))
self.additionalPlayerAudioMix = audioMix self.additionalPlayerAudioMixes = [audioMix]
(self.renderer.textureSource as? UniversalTextureSource)?.setAdditionalInputs([.video(playerItem, nil)]) (self.renderer.textureSource as? UniversalTextureSource)?.setAdditionalInputs([.video(playerItem, nil)])
} }
@ -1991,11 +2001,21 @@ public final class MediaEditor {
} }
} }
if let audioMix = self.additionalPlayerAudioMix, let asset = self.additionalPlayers.first?.currentItem?.asset { if let trackId {
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first) if let index = self.playerIndexForTrackId(trackId), index < self.additionalPlayerAudioMixes.count && index < self.additionalPlayers.count, let asset = self.additionalPlayers[index].currentItem?.asset {
audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero) let audioMix = self.additionalPlayerAudioMixes[index]
audioMix.inputParameters = [audioMixInputParameters] let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
self.additionalPlayers.first?.currentItem?.audioMix = audioMix audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero)
audioMix.inputParameters = [audioMixInputParameters]
self.additionalPlayers[index].currentItem?.audioMix = audioMix
}
} else {
if let audioMix = self.additionalPlayerAudioMixes.first, let asset = self.additionalPlayers.first?.currentItem?.asset {
let audioMixInputParameters = AVMutableAudioMixInputParameters(track: asset.tracks(withMediaType: .audio).first)
audioMixInputParameters.setVolume(Float(volume ?? 1.0), at: .zero)
audioMix.inputParameters = [audioMixInputParameters]
self.additionalPlayers.first?.currentItem?.audioMix = audioMix
}
} }
} }

View File

@ -1091,17 +1091,17 @@ private class TrackView: UIView, UIScrollViewDelegate, UIGestureRecognizerDelega
self.videoTransparentFramesContainer.layer.cornerRadius = framesCornerRadius self.videoTransparentFramesContainer.layer.cornerRadius = framesCornerRadius
self.videoOpaqueFramesContainer.layer.cornerRadius = framesCornerRadius self.videoOpaqueFramesContainer.layer.cornerRadius = framesCornerRadius
let scrubberSize = CGSize(width: availableSize.width, height: isSelected ? fullTrackHeight : collapsedTrackHeight) let scrubberSize = CGSize(width: availableSize.width, height: isSelected ? fullTrackHeight : collapsedTrackHeight)
var screenSpanDuration = duration var screenSpanDuration = duration
if track.isAudio && track.isMain { if track.isAudio && track.isMain && !track.isTimeline {
screenSpanDuration = min(30.0, track.duration) screenSpanDuration = min(30.0, track.duration)
} }
let minimalAudioWidth = handleWidth * 2.0 let minimalAudioWidth = handleWidth * 2.0
var containerTotalWidth = scrubberSize.width var containerTotalWidth = scrubberSize.width
if track.isAudio || !track.isMain, screenSpanDuration > 0.0 {
if !track.isTimeline, track.isAudio || !track.isMain, screenSpanDuration > 0.0 {
let trackFraction = track.duration / screenSpanDuration let trackFraction = track.duration / screenSpanDuration
if trackFraction < 1.0 - .ulpOfOne || trackFraction > 1.0 + .ulpOfOne { if trackFraction < 1.0 - .ulpOfOne || trackFraction > 1.0 + .ulpOfOne {
containerTotalWidth = max(minimalAudioWidth, ceil(availableSize.width * trackFraction)) containerTotalWidth = max(minimalAudioWidth, ceil(availableSize.width * trackFraction))
@ -1765,4 +1765,12 @@ private extension MediaScrubberComponent.Track {
return false return false
} }
} }
var isTimeline: Bool {
if case let .audio(_, _, _, _, isTimeline) = self.content {
return isTimeline
} else {
return false
}
}
} }

View File

@ -339,7 +339,8 @@ func canReplyInChat(_ chatPresentationInterfaceState: ChatPresentationInterfaceS
case .peer: case .peer:
if let channel = peer as? TelegramChannel { if let channel = peer as? TelegramChannel {
if case .member = channel.participationStatus { if case .member = channel.participationStatus {
canReply = channel.hasPermission(.sendSomething) let canBypassRestrictions = canBypassRestrictions(chatPresentationInterfaceState: chatPresentationInterfaceState)
canReply = channel.hasPermission(.sendSomething, ignoreDefault: canBypassRestrictions)
} }
if case .broadcast = channel.info { if case .broadcast = channel.info {
canReply = true canReply = true

View File

@ -9,16 +9,6 @@ import ChatBotStartInputPanelNode
import ChatChannelSubscriberInputPanelNode import ChatChannelSubscriberInputPanelNode
import ChatMessageSelectionInputPanelNode import ChatMessageSelectionInputPanelNode
func canBypassRestrictions(chatPresentationInterfaceState: ChatPresentationInterfaceState) -> Bool {
guard let boostsToUnrestrict = chatPresentationInterfaceState.boostsToUnrestrict else {
return false
}
if let appliedBoosts = chatPresentationInterfaceState.appliedBoosts, appliedBoosts >= boostsToUnrestrict {
return true
}
return false
}
func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatInputPanelNode?, currentSecondaryPanel: ChatInputPanelNode?, textInputPanelNode: ChatTextInputPanelNode?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> (primary: ChatInputPanelNode?, secondary: ChatInputPanelNode?) { func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatInputPanelNode?, currentSecondaryPanel: ChatInputPanelNode?, textInputPanelNode: ChatTextInputPanelNode?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> (primary: ChatInputPanelNode?, secondary: ChatInputPanelNode?) {
if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil { if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil {
return (nil, nil) return (nil, nil)