Various improvements

This commit is contained in:
Ilya Laktyushin 2026-03-29 16:23:09 +02:00
parent ceceec2e94
commit f160fb99d9
15 changed files with 148 additions and 39 deletions

View file

@ -16160,3 +16160,9 @@ Error: %8$@";
"MediaPlayer.PlaylistYourTitle" = "Your Playlist";
"MediaPlayer.AudioForwardedToSavedMesagesTooltip" = "Audio forwarded to Saved Messages.";
"Attachment.ProfileMusic" = "PROFILE MUSIC";
"Attachment.ChatsMusic" = "YOUR CHATS";
"Attachment.PublicMusic" = "PUBLIC CHATS";
"PeerInfo.UnofficialSecurityRisk" = "%@ uses an unofficial Telegram client messages to this user may be less secure.";

View file

@ -1780,10 +1780,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate, ASGestureRecog
}
private func updateMediaAccessoryPanel(frame: CGRect?, transition: ContainedViewLayoutTransition) {
guard case .glass = self.panelStyle,
self.hasMediaAccessoryPanel,
let frame,
let (item, previousItem, nextItem, order, type, _) = self.playlistStateAndType else {
guard case .glass = self.panelStyle, self.hasMediaAccessoryPanel, let frame, let (item, previousItem, nextItem, order, type, _) = self.playlistStateAndType else {
self.dismissMediaAccessoryPanel(transition: transition)
return
}
@ -1825,6 +1822,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate, ASGestureRecog
transition.updateFrame(node: mediaAccessoryPanel, frame: frame)
mediaAccessoryPanel.updateLayout(size: frame.size, leftInset: inset, rightInset: inset, isHidden: false, transition: transition)
}
transition.updateAlpha(node: mediaAccessoryPanel.containerNode.headerNode.separatorNode, alpha: self.hideButtons ? 0.0 : 1.0)
}
func updateBackgroundAlpha(_ alpha: CGFloat, transition: ContainedViewLayoutTransition) {

View file

@ -17,6 +17,11 @@ public enum InfoListItemLinkAction {
}
public class InfoListItem: ListViewItem {
public enum InfoStyle {
case `default`
case compact
}
public let selectable: Bool = false
let presentationData: ItemListPresentationData
@ -26,10 +31,11 @@ public class InfoListItem: ListViewItem {
let style: ItemListStyle
let hasDecorations: Bool
let isWarning: Bool
let infoStyle: InfoStyle
let linkAction: ((InfoListItemLinkAction) -> Void)?
let closeAction: (() -> Void)?
public init(presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .legacy, title: String, text: InfoListItemText, style: ItemListStyle, hasDecorations: Bool = true, isWarning: Bool = false, linkAction: ((InfoListItemLinkAction) -> Void)? = nil, closeAction: (() -> Void)?) {
public init(presentationData: ItemListPresentationData, systemStyle: ItemListSystemStyle = .legacy, title: String, text: InfoListItemText, style: ItemListStyle, hasDecorations: Bool = true, isWarning: Bool = false, infoStyle: InfoStyle = .default, linkAction: ((InfoListItemLinkAction) -> Void)? = nil, closeAction: (() -> Void)?) {
self.presentationData = presentationData
self.systemStyle = systemStyle
self.title = title
@ -37,6 +43,7 @@ public class InfoListItem: ListViewItem {
self.style = style
self.hasDecorations = hasDecorations
self.isWarning = isWarning
self.infoStyle = infoStyle
self.linkAction = linkAction
self.closeAction = closeAction
}
@ -226,6 +233,7 @@ public class InfoItemNode: ListViewItemNode {
let smallerTextFont = Font.regular(item.presentationData.fontSize.itemListBaseLabelFontSize / 14.0 * 15.0)
let textFont = Font.regular(item.presentationData.fontSize.itemListBaseLabelFontSize / 14.0 * 16.0)
let textBoldFont = Font.semibold(item.presentationData.fontSize.itemListBaseLabelFontSize / 14.0 * 16.0)
let smallBadgeFont = Font.semibold(11.0)
let badgeFont = Font.regular(15.0)
let largeBadgeFont = Font.regular(24.0)
@ -234,7 +242,18 @@ public class InfoItemNode: ListViewItemNode {
var updatedCloseIcon: UIImage?
let badgeDiameter: CGFloat = item.isWarning ? 30.0 : 22.0
let badgeDiameter: CGFloat
let effectiveBadgeFont: UIFont
if item.isWarning {
badgeDiameter = 30.0
effectiveBadgeFont = largeBadgeFont
} else if case .compact = item.infoStyle {
badgeDiameter = 15.0
effectiveBadgeFont = smallBadgeFont
} else {
badgeDiameter = 22.0
effectiveBadgeFont = badgeFont
}
if currentItem?.presentationData.theme !== item.presentationData.theme {
updatedTheme = item.presentationData.theme
updatedBadgeImage = generateStretchableFilledCircleImage(diameter: badgeDiameter, color: item.presentationData.theme.list.itemDestructiveColor)
@ -267,21 +286,33 @@ public class InfoItemNode: ListViewItemNode {
case let .plain(text):
attributedText = NSAttributedString(string: text, font: textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor)
case let .markdown(text):
attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: item.isWarning ? smallerTextFont : textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), bold: MarkdownAttributeSet(font: textBoldFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), link: MarkdownAttributeSet(font: textFont, textColor: item.presentationData.theme.list.itemAccentColor), linkAttribute: { contents in
attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: item.isWarning || item.infoStyle == .compact ? smallerTextFont : textFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), bold: MarkdownAttributeSet(font: textBoldFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), link: MarkdownAttributeSet(font: textFont, textColor: item.presentationData.theme.list.itemAccentColor), linkAttribute: { contents in
return (TelegramTextAttributes.URL, contents)
}))
}
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.isWarning ? "⚠️" : "!", font: item.isWarning ? largeBadgeFont : badgeFont, textColor: item.presentationData.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 3, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
var textCutout: TextNodeCutout?
if case .compact = item.infoStyle, item.title.isEmpty {
textCutout = TextNodeCutout(topLeft: CGSize(width: 22.0, height: 8.0), topRight: nil, bottomRight: nil)
}
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.isWarning ? "⚠️" : "!", font: effectiveBadgeFont, textColor: item.presentationData.theme.list.itemCheckColors.foregroundColor), backgroundColor: nil, maximumNumberOfLines: 3, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset - badgeDiameter - 8.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: textCutout, insets: UIEdgeInsets()))
var verticalInset: CGFloat = 0.0
if case .glass = item.systemStyle {
verticalInset = 4.0
}
let contentSize = CGSize(width: params.width, height: titleLayout.size.height + textLayout.size.height + 38.0 + verticalInset * 2.0)
var contentHeight: CGFloat = titleLayout.size.height + textLayout.size.height + verticalInset * 2.0
if case .compact = item.infoStyle {
contentHeight += 13.0
} else {
contentHeight += 38.0
}
let contentSize = CGSize(width: params.width, height: contentHeight)
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
return (layout, { [weak self] in
@ -345,6 +376,9 @@ public class InfoItemNode: ListViewItemNode {
bottomStripeInset = leftInset
if !item.hasDecorations {
strongSelf.topStripeNode.isHidden = true
if case .compact = item.infoStyle {
strongSelf.bottomStripeNode.isHidden = true
}
}
}
@ -369,13 +403,34 @@ public class InfoItemNode: ListViewItemNode {
strongSelf.closeButton.setImage(updatedCloseIcon, for: [])
}
strongSelf.badgeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: verticalInset + 15.0 + (item.isWarning ? 4.0 : 0.0)), size: CGSize(width: badgeDiameter, height: badgeDiameter))
var badgeOriginX: CGFloat = leftInset
let badgeOriginY: CGFloat
var labelOffset: CGPoint = .zero
if item.isWarning {
badgeOriginY = verticalInset + 15.0 + 4.0
} else if case .compact = item.infoStyle {
badgeOriginY = 12.0
badgeOriginX += 1
labelOffset = CGPoint(x: UIScreenPixel, y: -1.0)
} else {
badgeOriginY = verticalInset + 15.0
}
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: strongSelf.badgeNode.frame.midX - labelLayout.size.width / 2.0, y: strongSelf.badgeNode.frame.minY + 2.0 + UIScreenPixel), size: labelLayout.size)
strongSelf.badgeNode.frame = CGRect(origin: CGPoint(x: badgeOriginX, y: badgeOriginY), size: CGSize(width: badgeDiameter, height: badgeDiameter))
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(strongSelf.badgeNode.frame.midX - labelLayout.size.width / 2.0) + labelOffset.x, y: strongSelf.badgeNode.frame.minY + 2.0 + UIScreenPixel + labelOffset.y), size: labelLayout.size)
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: strongSelf.badgeNode.frame.maxX + 8.0, y: verticalInset + 16.0), size: titleLayout.size)
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + 9.0), size: textLayout.size)
let textOriginY: CGFloat
if titleLayout.size.height > 0.0 {
textOriginY = strongSelf.titleNode.frame.maxY + 9.0
} else if case .compact = item.infoStyle {
textOriginY = 11.0
} else {
textOriginY = verticalInset + 16.0
}
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: textOriginY), size: textLayout.size)
strongSelf.closeButton.frame = CGRect(x: params.width - rightInset - 26.0, y: verticalInset + 10.0, width: 32.0, height: 32.0)
}

View file

@ -561,7 +561,13 @@ public final class ListMessageFileItemNode: ListMessageNode {
guard let item = self.item, let message = item.message else {
return
}
item.interaction.toggleMediaPlayback?(message)
if let resourceStatus = self.resourceStatus, case .playbackStatus = resourceStatus {
if let context = self.context {
context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: nil)
}
} else {
item.interaction.toggleMediaPlayback?(message)
}
}
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
@ -1696,7 +1702,11 @@ public final class ListMessageFileItemNode: ListMessageNode {
}
case .playbackStatus:
if let context = self.context {
context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: nil)
if let item = self.item, let message = item.message, let interaction = self.interaction, item.isStoryMusic {
let _ = interaction.openMessage(message, .default)
} else {
context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: nil)
}
}
}
}

View file

@ -1065,7 +1065,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1898850301] = { return Api.StoriesStealthMode.parse_storiesStealthMode($0) }
dict[-1826262950] = { return Api.StoryAlbum.parse_storyAlbum($0) }
dict[-1205411504] = { return Api.StoryFwdHeader.parse_storyFwdHeader($0) }
dict[-302947087] = { return Api.StoryItem.parse_storyItem($0) }
dict[379894076] = { return Api.StoryItem.parse_storyItem($0) }
dict[1374088783] = { return Api.StoryItem.parse_storyItemDeleted($0) }
dict[-5388013] = { return Api.StoryItem.parse_storyItemSkipped($0) }
dict[1620104917] = { return Api.StoryReaction.parse_storyReaction($0) }

View file

@ -430,7 +430,8 @@ public extension Api {
public var views: Api.StoryViews?
public var sentReaction: Api.Reaction?
public var albums: [Int32]?
public init(flags: Int32, id: Int32, date: Int32, fromId: Api.Peer?, fwdFrom: Api.StoryFwdHeader?, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?, albums: [Int32]?) {
public var music: Api.Document?
public init(flags: Int32, id: Int32, date: Int32, fromId: Api.Peer?, fwdFrom: Api.StoryFwdHeader?, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?, albums: [Int32]?, music: Api.Document?) {
self.flags = flags
self.id = id
self.date = date
@ -445,9 +446,10 @@ public extension Api {
self.views = views
self.sentReaction = sentReaction
self.albums = albums
self.music = music
}
public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) {
return ("storyItem", [("flags", ConstructorParameterDescription(self.flags)), ("id", ConstructorParameterDescription(self.id)), ("date", ConstructorParameterDescription(self.date)), ("fromId", ConstructorParameterDescription(self.fromId)), ("fwdFrom", ConstructorParameterDescription(self.fwdFrom)), ("expireDate", ConstructorParameterDescription(self.expireDate)), ("caption", ConstructorParameterDescription(self.caption)), ("entities", ConstructorParameterDescription(self.entities)), ("media", ConstructorParameterDescription(self.media)), ("mediaAreas", ConstructorParameterDescription(self.mediaAreas)), ("privacy", ConstructorParameterDescription(self.privacy)), ("views", ConstructorParameterDescription(self.views)), ("sentReaction", ConstructorParameterDescription(self.sentReaction)), ("albums", ConstructorParameterDescription(self.albums))])
return ("storyItem", [("flags", ConstructorParameterDescription(self.flags)), ("id", ConstructorParameterDescription(self.id)), ("date", ConstructorParameterDescription(self.date)), ("fromId", ConstructorParameterDescription(self.fromId)), ("fwdFrom", ConstructorParameterDescription(self.fwdFrom)), ("expireDate", ConstructorParameterDescription(self.expireDate)), ("caption", ConstructorParameterDescription(self.caption)), ("entities", ConstructorParameterDescription(self.entities)), ("media", ConstructorParameterDescription(self.media)), ("mediaAreas", ConstructorParameterDescription(self.mediaAreas)), ("privacy", ConstructorParameterDescription(self.privacy)), ("views", ConstructorParameterDescription(self.views)), ("sentReaction", ConstructorParameterDescription(self.sentReaction)), ("albums", ConstructorParameterDescription(self.albums)), ("music", ConstructorParameterDescription(self.music))])
}
}
public class Cons_storyItemDeleted: TypeConstructorDescription {
@ -482,7 +484,7 @@ public extension Api {
switch self {
case .storyItem(let _data):
if boxed {
buffer.appendInt32(-302947087)
buffer.appendInt32(379894076)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt32(_data.id, buffer: buffer, boxed: false)
@ -532,6 +534,9 @@ public extension Api {
serializeInt32(item, buffer: buffer, boxed: false)
}
}
if Int(_data.flags) & Int(1 << 20) != 0 {
_data.music!.serialize(buffer, true)
}
break
case .storyItemDeleted(let _data):
if boxed {
@ -554,7 +559,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, ConstructorParameterDescription)]) {
switch self {
case .storyItem(let _data):
return ("storyItem", [("flags", ConstructorParameterDescription(_data.flags)), ("id", ConstructorParameterDescription(_data.id)), ("date", ConstructorParameterDescription(_data.date)), ("fromId", ConstructorParameterDescription(_data.fromId)), ("fwdFrom", ConstructorParameterDescription(_data.fwdFrom)), ("expireDate", ConstructorParameterDescription(_data.expireDate)), ("caption", ConstructorParameterDescription(_data.caption)), ("entities", ConstructorParameterDescription(_data.entities)), ("media", ConstructorParameterDescription(_data.media)), ("mediaAreas", ConstructorParameterDescription(_data.mediaAreas)), ("privacy", ConstructorParameterDescription(_data.privacy)), ("views", ConstructorParameterDescription(_data.views)), ("sentReaction", ConstructorParameterDescription(_data.sentReaction)), ("albums", ConstructorParameterDescription(_data.albums))])
return ("storyItem", [("flags", ConstructorParameterDescription(_data.flags)), ("id", ConstructorParameterDescription(_data.id)), ("date", ConstructorParameterDescription(_data.date)), ("fromId", ConstructorParameterDescription(_data.fromId)), ("fwdFrom", ConstructorParameterDescription(_data.fwdFrom)), ("expireDate", ConstructorParameterDescription(_data.expireDate)), ("caption", ConstructorParameterDescription(_data.caption)), ("entities", ConstructorParameterDescription(_data.entities)), ("media", ConstructorParameterDescription(_data.media)), ("mediaAreas", ConstructorParameterDescription(_data.mediaAreas)), ("privacy", ConstructorParameterDescription(_data.privacy)), ("views", ConstructorParameterDescription(_data.views)), ("sentReaction", ConstructorParameterDescription(_data.sentReaction)), ("albums", ConstructorParameterDescription(_data.albums)), ("music", ConstructorParameterDescription(_data.music))])
case .storyItemDeleted(let _data):
return ("storyItemDeleted", [("id", ConstructorParameterDescription(_data.id))])
case .storyItemSkipped(let _data):
@ -627,6 +632,12 @@ public extension Api {
_14 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
}
}
var _15: Api.Document?
if Int(_1!) & Int(1 << 20) != 0 {
if let signature = reader.readInt32() {
_15 = Api.parse(reader, signature: signature) as? Api.Document
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -641,8 +652,9 @@ public extension Api {
let _c12 = (Int(_1!) & Int(1 << 3) == 0) || _12 != nil
let _c13 = (Int(_1!) & Int(1 << 15) == 0) || _13 != nil
let _c14 = (Int(_1!) & Int(1 << 19) == 0) || _14 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 {
return Api.StoryItem.storyItem(Cons_storyItem(flags: _1!, id: _2!, date: _3!, fromId: _4, fwdFrom: _5, expireDate: _6!, caption: _7, entities: _8, media: _9!, mediaAreas: _10, privacy: _11, views: _12, sentReaction: _13, albums: _14))
let _c15 = (Int(_1!) & Int(1 << 20) == 0) || _15 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 {
return Api.StoryItem.storyItem(Cons_storyItem(flags: _1!, id: _2!, date: _3!, fromId: _4, fwdFrom: _5, expireDate: _6!, caption: _7, entities: _8, media: _9!, mediaAreas: _10, privacy: _11, views: _12, sentReaction: _13, albums: _14, music: _15))
}
else {
return nil

View file

@ -12788,9 +12788,9 @@ public extension Api.functions.stories {
}
}
public extension Api.functions.stories {
static func editStory(flags: Int32, peer: Api.InputPeer, id: Int32, media: Api.InputMedia?, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
static func editStory(flags: Int32, peer: Api.InputPeer, id: Int32, media: Api.InputMedia?, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule]?, music: Api.InputDocument?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(-1249658298)
buffer.appendInt32(744728363)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
@ -12821,7 +12821,10 @@ public extension Api.functions.stories {
item.serialize(buffer, true)
}
}
return (FunctionDescription(name: "stories.editStory", parameters: [("flags", ConstructorParameterDescription(flags)), ("peer", ConstructorParameterDescription(peer)), ("id", ConstructorParameterDescription(id)), ("media", ConstructorParameterDescription(media)), ("mediaAreas", ConstructorParameterDescription(mediaAreas)), ("caption", ConstructorParameterDescription(caption)), ("entities", ConstructorParameterDescription(entities)), ("privacyRules", ConstructorParameterDescription(privacyRules))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
if Int(flags) & Int(1 << 4) != 0 {
music!.serialize(buffer, true)
}
return (FunctionDescription(name: "stories.editStory", parameters: [("flags", ConstructorParameterDescription(flags)), ("peer", ConstructorParameterDescription(peer)), ("id", ConstructorParameterDescription(id)), ("media", ConstructorParameterDescription(media)), ("mediaAreas", ConstructorParameterDescription(mediaAreas)), ("caption", ConstructorParameterDescription(caption)), ("entities", ConstructorParameterDescription(entities)), ("privacyRules", ConstructorParameterDescription(privacyRules)), ("music", ConstructorParameterDescription(music))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
@ -13204,9 +13207,9 @@ public extension Api.functions.stories {
}
}
public extension Api.functions.stories {
static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?, fwdFromId: Api.InputPeer?, fwdFromStory: Int32?, albums: [Int32]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?, fwdFromId: Api.InputPeer?, fwdFromStory: Int32?, albums: [Int32]?, music: Api.InputDocument?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(1937752812)
buffer.appendInt32(-1885443944)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
media.serialize(buffer, true)
@ -13249,7 +13252,10 @@ public extension Api.functions.stories {
serializeInt32(item, buffer: buffer, boxed: false)
}
}
return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", ConstructorParameterDescription(flags)), ("peer", ConstructorParameterDescription(peer)), ("media", ConstructorParameterDescription(media)), ("mediaAreas", ConstructorParameterDescription(mediaAreas)), ("caption", ConstructorParameterDescription(caption)), ("entities", ConstructorParameterDescription(entities)), ("privacyRules", ConstructorParameterDescription(privacyRules)), ("randomId", ConstructorParameterDescription(randomId)), ("period", ConstructorParameterDescription(period)), ("fwdFromId", ConstructorParameterDescription(fwdFromId)), ("fwdFromStory", ConstructorParameterDescription(fwdFromStory)), ("albums", ConstructorParameterDescription(albums))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
if Int(flags) & Int(1 << 9) != 0 {
music!.serialize(buffer, true)
}
return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", ConstructorParameterDescription(flags)), ("peer", ConstructorParameterDescription(peer)), ("media", ConstructorParameterDescription(media)), ("mediaAreas", ConstructorParameterDescription(mediaAreas)), ("caption", ConstructorParameterDescription(caption)), ("entities", ConstructorParameterDescription(entities)), ("privacyRules", ConstructorParameterDescription(privacyRules)), ("randomId", ConstructorParameterDescription(randomId)), ("period", ConstructorParameterDescription(period)), ("fwdFromId", ConstructorParameterDescription(fwdFromId)), ("fwdFromStory", ConstructorParameterDescription(fwdFromStory)), ("albums", ConstructorParameterDescription(albums)), ("music", ConstructorParameterDescription(music))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {

View file

@ -176,7 +176,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, ASScrollVi
}
}
private let separatorNode: ASDisplayNode
public let separatorNode: ASDisplayNode
private var tapRecognizer: UITapGestureRecognizer?

View file

@ -629,6 +629,7 @@ public struct CachedUserFlags: OptionSet {
public static let displayGiftButton = CachedUserFlags(rawValue: 1 << 7)
public static let myCopyProtectionEnabled = CachedUserFlags(rawValue: 1 << 8)
public static let copyProtectionEnabled = CachedUserFlags(rawValue: 1 << 9)
public static let unofficialSecurityRisk = CachedUserFlags(rawValue: 1 << 10)
}
public final class EditableBotInfo: PostboxCoding, Equatable {

View file

@ -1373,6 +1373,8 @@ func _internal_uploadStoryImpl(
flags |= 1 << 8
}
//var apiMusic: Api.InputDocument?
return network.request(Api.functions.stories.sendStory(
flags: flags,
peer: inputPeer,
@ -1385,7 +1387,8 @@ func _internal_uploadStoryImpl(
period: Int32(period),
fwdFromId: fwdFromId,
fwdFromStory: fwdFromStory,
albums: folders.isEmpty ? nil : folders.map(Int32.init(clamping:))
albums: folders.isEmpty ? nil : folders.map(Int32.init(clamping:)),
music: nil
))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
@ -1798,7 +1801,8 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
mediaAreas: inputMediaAreas,
caption: apiCaption,
entities: apiEntities,
privacyRules: privacyRules
privacyRules: privacyRules,
music: nil
))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
@ -1907,7 +1911,7 @@ func _internal_editStoryPrivacy(account: Account, id: Int32, privacy: EngineStor
var flags: Int32 = 0
flags |= 1 << 2
return account.network.request(Api.functions.stories.editStory(flags: flags, peer: .inputPeerSelf, id: id, media: nil, mediaAreas: nil, caption: nil, entities: nil, privacyRules: inputRules))
return account.network.request(Api.functions.stories.editStory(flags: flags, peer: .inputPeerSelf, id: id, media: nil, mediaAreas: nil, caption: nil, entities: nil, privacyRules: inputRules, music: nil))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)

View file

@ -299,6 +299,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
let displayGiftButton = (userFullFlags2 & (1 << 16)) != 0
let myCopyProtectionEnabled = (userFullFlags2 & (1 << 23)) != 0
let copyProtectionEnabled = (userFullFlags2 & (1 << 24)) != 0
let unofficialSecurityRisk = (userFullFlags2 & (1 << 26)) != 0
var flags: CachedUserFlags = previous.flags
if premiumRequired {
@ -346,6 +347,11 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
} else {
flags.remove(.copyProtectionEnabled)
}
if unofficialSecurityRisk {
flags.insert(.unofficialSecurityRisk)
} else {
flags.remove(.unofficialSecurityRisk)
}
let callsPrivate = (userFullFlags & (1 << 5)) != 0
let canPinMessages = (userFullFlags & (1 << 7)) != 0

View file

@ -337,12 +337,12 @@ private func attachmentFileControllerEntries(
case .recent:
listTitle = presentationData.strings.Attachment_RecentlySentFiles
case .audio:
listTitle = presentationData.strings.Attachment_SharedAudio
listTitle = presentationData.strings.Attachment_ChatsMusic
}
if case let .audio(audioMode) = mode, audioMode != .savedMusic {
if let savedMusic, savedMusic.count > 0 {
entries.append(.savedHeader(presentationData.theme, presentationData.strings.MediaEditor_Audio_SavedMusic.uppercased()))
entries.append(.savedHeader(presentationData.theme, presentationData.strings.Attachment_ProfileMusic.uppercased()))
var savedMusic = savedMusic
var hasShowMore = false

View file

@ -484,11 +484,13 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
send(message)
self?.listNode.clearHighlightAnimated(true)
},
toggleMediaPlayback: { message in
toggleMediaPlayback: { [weak self] message in
didPreviewAudio()
let playlistLocation: PeerMessagesPlaylistLocation = .custom(messages: .single(([message], 0, false)), canReorder: false, at: message.id, loadMore: nil, hidePanel: true)
context.sharedContext.mediaManager.setPlaylist((context, PeerMessagesMediaPlaylist(context: context, location: playlistLocation, chatLocationContextHolder: nil)), type: .music, control: .playback(.togglePlayPause))
self?.view.window?.endEditing(true)
},
expandSection: { [weak self] section in
self?.expandedSections.insert(section)
@ -631,7 +633,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
var index: Int32 = 0
if let savedMusic, !savedMusic.isEmpty {
entries.append(.header(title: "PROFILE MUSIC", section: section))
entries.append(.header(title: presentationData.strings.Attachment_ProfileMusic, section: section))
var savedMusic = savedMusic
var hasShowMore = false
@ -652,7 +654,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
section += 1
if !messages.isEmpty {
entries.append(.header(title: "YOUR CHATS", section: section))
entries.append(.header(title: presentationData.strings.Attachment_ChatsMusic, section: section))
var messages = messages
var hasShowMore = false
if messages.count > 4 && !expandedSections.contains(section) {
@ -672,7 +674,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
index = 0
section += 1
entries.append(.header(title: "PUBLIC CHATS", section: section))
entries.append(.header(title: presentationData.strings.Attachment_PublicMusic, section: section))
for message in globalMusic {
entries.append(.file(index: index, message: message, section: section))
index += 1

View file

@ -15,6 +15,7 @@ final class PeerInfoScreenInfoItem: PeerInfoScreenItem {
let title: String
let text: InfoListItemText
let isWarning: Bool
let style: InfoListItem.InfoStyle
let linkAction: ((InfoListItemLinkAction) -> Void)?
init(
@ -22,12 +23,14 @@ final class PeerInfoScreenInfoItem: PeerInfoScreenItem {
title: String,
text: InfoListItemText,
isWarning: Bool = false,
style: InfoListItem.InfoStyle = .default,
linkAction: ((InfoListItemLinkAction) -> Void)?
) {
self.id = id
self.title = title
self.text = text
self.isWarning = isWarning
self.style = style
self.linkAction = linkAction
}
@ -67,7 +70,7 @@ private final class PeerInfoScreenInfoItemNode: PeerInfoScreenItemNode {
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
let infoItem = InfoListItem(presentationData: ItemListPresentationData(presentationData), systemStyle: .glass, title: item.title, text: item.text, style: .blocks, hasDecorations: false, isWarning: item.isWarning, linkAction: { link in
let infoItem = InfoListItem(presentationData: ItemListPresentationData(presentationData), systemStyle: .glass, title: item.title, text: item.text, style: .blocks, hasDecorations: false, isWarning: item.isWarning, infoStyle: item.style, linkAction: { link in
item.linkAction?(link)
}, closeAction: nil)
let params = ListViewItemLayoutParams(width: width, leftInset: safeInsets.left, rightInset: safeInsets.right, availableHeight: 1000.0)

View file

@ -22,6 +22,7 @@ private let enabledPublicBioEntities: EnabledEntityTypes = [.allUrl, .mention, .
private let enabledPrivateBioEntities: EnabledEntityTypes = [.internalUrl, .mention, .hashtag]
enum InfoSection: Int, CaseIterable {
case unofficial
case groupLocation
case calls
case personalChannel
@ -98,6 +99,10 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
let ItemBotAddToChatInfo = 9003
let ItemVerification = 9004
if let cachedUserData = data.cachedData as? CachedUserData, cachedUserData.flags.contains(.unofficialSecurityRisk) {
items[.unofficial]!.append(PeerInfoScreenInfoItem(id: 0, title: "", text: .markdown(presentationData.strings.PeerInfo_UnofficialSecurityRisk(EnginePeer(user).compactDisplayTitle).string), style: .compact, linkAction: nil))
}
if !callMessages.isEmpty {
items[.calls]!.append(PeerInfoScreenCallListItem(id: ItemCallList, messages: callMessages))
}