Various improvements
This commit is contained in:
parent
6aa99e3553
commit
8098f24f4e
26 changed files with 251 additions and 75 deletions
|
|
@ -15983,3 +15983,12 @@ Error: %8$@";
|
||||||
"Notification.PollAddedOptionYou" = "You added the option \"%1$@\" to the poll";
|
"Notification.PollAddedOptionYou" = "You added the option \"%1$@\" to the poll";
|
||||||
|
|
||||||
"Notification.ManagedBotCreated" = "%@ bot created";
|
"Notification.ManagedBotCreated" = "%@ bot created";
|
||||||
|
|
||||||
|
"Chat.PolOptionAddedTimestamp.Date" = "Added by %1$@ %2$@";
|
||||||
|
"Chat.PolOptionAddedTimestamp.TodayAt" = "Added by %1$@ today at %2$@";
|
||||||
|
"Chat.PolOptionAddedTimestamp.YesterdayAt" = "Added by %1$@ yesterday at %2$@";
|
||||||
|
|
||||||
|
|
||||||
|
"Chat.PolOptionAddedTimestampYou.Date" = "Added by you %1$@";
|
||||||
|
"Chat.PolOptionAddedTimestampYou.TodayAt" = "Added by you today at %1$@";
|
||||||
|
"Chat.PolOptionAddedTimestampYou.YesterdayAt" = "Added by you yesterday at %1$@";
|
||||||
|
|
|
||||||
|
|
@ -1390,7 +1390,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||||
func makeBirthdayPrivacyController(context: AccountContext, settings: Promise<AccountPrivacySettings?>, openedFromBirthdayScreen: Bool, present: @escaping (ViewController) -> Void)
|
func makeBirthdayPrivacyController(context: AccountContext, settings: Promise<AccountPrivacySettings?>, openedFromBirthdayScreen: Bool, present: @escaping (ViewController) -> Void)
|
||||||
func makeSetupTwoFactorAuthController(context: AccountContext) -> ViewController
|
func makeSetupTwoFactorAuthController(context: AccountContext) -> ViewController
|
||||||
func makeStorageManagementController(context: AccountContext) -> ViewController
|
func makeStorageManagementController(context: AccountContext) -> ViewController
|
||||||
func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, audio: Bool, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, presentDocumentScanner: (() -> Void)?, send: @escaping ([AnyMediaReference]) -> Void) -> AttachmentFileController
|
func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, audio: Bool, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, presentDocumentScanner: (() -> Void)?, send: @escaping ([AnyMediaReference], Bool, Int32?, NSAttributedString?) -> Void) -> AttachmentFileController
|
||||||
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, isScheduledMessages: Bool, isFile: Bool, hasTimer: Bool, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, isScheduledMessages: Bool, isFile: Bool, hasTimer: Bool, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
||||||
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, stories: Bool, forceDark: Bool) -> ViewController
|
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, stories: Bool, forceDark: Bool) -> ViewController
|
||||||
func makeStorySearchController(context: AccountContext, scope: StorySearchControllerScope, listContext: SearchStoryListContext?) -> ViewController
|
func makeStorySearchController(context: AccountContext, scope: StorySearchControllerScope, listContext: SearchStoryListContext?) -> ViewController
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ public enum ChatControllerInteractionLongTapAction {
|
||||||
|
|
||||||
public enum ChatHistoryMessageSelection: Equatable {
|
public enum ChatHistoryMessageSelection: Equatable {
|
||||||
case none
|
case none
|
||||||
case selectable(selected: Bool)
|
case selectable(selected: Bool, num: Int?)
|
||||||
|
|
||||||
public static func ==(lhs: ChatHistoryMessageSelection, rhs: ChatHistoryMessageSelection) -> Bool {
|
public static func ==(lhs: ChatHistoryMessageSelection, rhs: ChatHistoryMessageSelection) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
|
|
@ -273,8 +273,8 @@ public enum ChatHistoryMessageSelection: Equatable {
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .selectable(selected):
|
case let .selectable(selected, num):
|
||||||
if case .selectable(selected) = rhs {
|
if case .selectable(selected, num) = rhs {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -1148,7 +1148,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let selection: ChatHistoryMessageSelection = selected.flatMap { .selectable(selected: $0) } ?? .none
|
let selection: ChatHistoryMessageSelection = selected.flatMap { .selectable(selected: $0, num: nil) } ?? .none
|
||||||
var isMedia = false
|
var isMedia = false
|
||||||
if let tagMask, tagMask != .photoOrVideo {
|
if let tagMask, tagMask != .photoOrVideo {
|
||||||
isMedia = true
|
isMedia = true
|
||||||
|
|
@ -5886,7 +5886,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||||
associatedStories: [:]
|
associatedStories: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: true, isGlobalSearchResult: true)
|
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false, num: nil) : .none, displayHeader: false, customHeader: nil, hintIsLink: true, isGlobalSearchResult: true)
|
||||||
case .files:
|
case .files:
|
||||||
var media: [EngineMedia] = []
|
var media: [EngineMedia] = []
|
||||||
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: 0, attributes: [.FileName(fileName: "Text.txt")], alternativeRepresentations: [])))
|
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: 0, attributes: [.FileName(fileName: "Text.txt")], alternativeRepresentations: [])))
|
||||||
|
|
@ -5917,7 +5917,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||||
associatedStories: [:]
|
associatedStories: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false, num: nil) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
||||||
case .music:
|
case .music:
|
||||||
var media: [EngineMedia] = []
|
var media: [EngineMedia] = []
|
||||||
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: false, duration: 0, title: nil, performer: nil, waveform: Data())], alternativeRepresentations: [])))
|
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: false, duration: 0, title: nil, performer: nil, waveform: Data())], alternativeRepresentations: [])))
|
||||||
|
|
@ -5948,7 +5948,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||||
associatedStories: [:]
|
associatedStories: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false, num: nil) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
||||||
case .voice, .instantVideo:
|
case .voice, .instantVideo:
|
||||||
var media: [EngineMedia] = []
|
var media: [EngineMedia] = []
|
||||||
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: true, duration: 0, title: nil, performer: nil, waveform: Data())], alternativeRepresentations: [])))
|
media.append(.file(TelegramMediaFile(fileId: EngineMedia.Id(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: true, duration: 0, title: nil, performer: nil, waveform: Data())], alternativeRepresentations: [])))
|
||||||
|
|
@ -5979,7 +5979,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode {
|
||||||
associatedStories: [:]
|
associatedStories: [:]
|
||||||
)
|
)
|
||||||
|
|
||||||
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(id: peer1.id), interaction: ListMessageItemInteraction.default, message: message._asMessage(), selection: hasSelection ? .selectable(selected: false, num: nil) : .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2395,7 +2395,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
selectionControlStyle = .compact
|
selectionControlStyle = .compact
|
||||||
}
|
}
|
||||||
|
|
||||||
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, item.selected, selectionControlStyle)
|
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, item.selected, selectionControlStyle, nil)
|
||||||
if promoInfo == nil && !isPeerGroup {
|
if promoInfo == nil && !isPeerGroup {
|
||||||
selectableControlSizeAndApply = sizeAndApply
|
selectableControlSizeAndApply = sizeAndApply
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,7 +184,7 @@ public final class BalancedTextComponent: Component {
|
||||||
|
|
||||||
var bestSize: (availableWidth: CGFloat, info: TextNodeLayout)
|
var bestSize: (availableWidth: CGFloat, info: TextNodeLayout)
|
||||||
|
|
||||||
let info = self.textView.updateLayoutFullInfo(availableSize)
|
let info = self.textView.updateLayoutFullInfo(availableSize)
|
||||||
bestSize = (availableSize.width, info)
|
bestSize = (availableSize.width, info)
|
||||||
|
|
||||||
if component.balanced && info.numberOfLines > 1 {
|
if component.balanced && info.numberOfLines > 1 {
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ public class ItemListAddressItemNode: ListViewItemNode {
|
||||||
var leftOffset: CGFloat = 0.0
|
var leftOffset: CGFloat = 0.0
|
||||||
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
||||||
if let selected = item.selected {
|
if let selected = item.selected {
|
||||||
let (selectionWidth, selectionApply) = selectionNodeLayout(item.theme.list.itemCheckColors.strokeColor, item.theme.list.itemCheckColors.fillColor, item.theme.list.itemCheckColors.foregroundColor, selected, .regular)
|
let (selectionWidth, selectionApply) = selectionNodeLayout(item.theme.list.itemCheckColors.strokeColor, item.theme.list.itemCheckColors.fillColor, item.theme.list.itemCheckColors.foregroundColor, selected, .regular, nil)
|
||||||
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
||||||
leftOffset += selectionWidth - 8.0
|
leftOffset += selectionWidth - 8.0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -451,7 +451,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||||
if case let .check(checked) = item.control {
|
if case let .check(checked) = item.control {
|
||||||
selected = checked
|
selected = checked
|
||||||
}
|
}
|
||||||
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .compact)
|
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .compact, nil)
|
||||||
selectableControlSizeAndApply = sizeAndApply
|
selectableControlSizeAndApply = sizeAndApply
|
||||||
editingOffset = sizeAndApply.0
|
editingOffset = sizeAndApply.0
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ public final class ItemListSelectableControlNode: ASDisplayNode {
|
||||||
self.addSubnode(self.checkNode)
|
self.addSubnode(self.checkNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ style: Style) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) {
|
public static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ style: Style, _ num: Int?) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) {
|
||||||
return { strokeColor, fillColor, foregroundColor, selected, style in
|
return { strokeColor, fillColor, foregroundColor, selected, style, num in
|
||||||
let resultNode: ItemListSelectableControlNode
|
let resultNode: ItemListSelectableControlNode
|
||||||
if let node = node {
|
if let node = node {
|
||||||
resultNode = node
|
resultNode = node
|
||||||
|
|
@ -53,6 +53,9 @@ public final class ItemListSelectableControlNode: ASDisplayNode {
|
||||||
checkOffset = 16.0
|
checkOffset = 16.0
|
||||||
}
|
}
|
||||||
resultNode.checkNode.frame = CGRect(origin: CGPoint(x: checkOffset, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize)
|
resultNode.checkNode.frame = CGRect(origin: CGPoint(x: checkOffset, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize)
|
||||||
|
if let num {
|
||||||
|
resultNode.checkNode.content = .counter(num)
|
||||||
|
}
|
||||||
resultNode.checkNode.setSelected(selected, animated: animated)
|
resultNode.checkNode.setSelected(selected, animated: animated)
|
||||||
return resultNode
|
return resultNode
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ public class ItemListTextWithLabelItemNode: ListViewItemNode {
|
||||||
var leftOffset: CGFloat = 0.0
|
var leftOffset: CGFloat = 0.0
|
||||||
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
||||||
if let selected = item.selected {
|
if let selected = item.selected {
|
||||||
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .regular)
|
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, selected, .regular, nil)
|
||||||
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
||||||
leftOffset += selectionWidth - 8.0
|
leftOffset += selectionWidth - 8.0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -638,8 +638,8 @@ public final class ListMessageFileItemNode: ListMessageNode {
|
||||||
|
|
||||||
var leftOffset: CGFloat = 0.0
|
var leftOffset: CGFloat = 0.0
|
||||||
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
||||||
if case let .selectable(selected) = item.selection {
|
if case let .selectable(selected, num) = item.selection {
|
||||||
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular)
|
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular, num.flatMap { $0 + 1 })
|
||||||
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
||||||
leftOffset += selectionWidth
|
leftOffset += selectionWidth
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,7 @@ public final class ListMessageItem: ListViewItem, ItemListItem {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .selectable(selected) = self.selection {
|
if case let .selectable(selected, _) = self.selection {
|
||||||
self.interaction.toggleMessagesSelection([message.id], !selected)
|
self.interaction.toggleMessagesSelection([message.id], !selected)
|
||||||
} else {
|
} else {
|
||||||
if !self.displayFileInfo || self.isAttachMusic {
|
if !self.displayFileInfo || self.isAttachMusic {
|
||||||
|
|
|
||||||
|
|
@ -267,8 +267,8 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
|
||||||
|
|
||||||
var leftOffset: CGFloat = 0.0
|
var leftOffset: CGFloat = 0.0
|
||||||
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)?
|
||||||
if case let .selectable(selected) = item.selection {
|
if case let .selectable(selected, num) = item.selection {
|
||||||
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular)
|
let (selectionWidth, selectionApply) = selectionNodeLayout(item.presentationData.theme.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.theme.list.itemCheckColors.fillColor, item.presentationData.theme.theme.list.itemCheckColors.foregroundColor, selected, .regular, num.flatMap { $0 + 1 })
|
||||||
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
selectionNodeWidthAndApply = (selectionWidth, selectionApply)
|
||||||
leftOffset += selectionWidth
|
leftOffset += selectionWidth
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode {
|
||||||
var editingOffset: CGFloat = 0.0
|
var editingOffset: CGFloat = 0.0
|
||||||
|
|
||||||
if let isSelected = item.isSelected {
|
if let isSelected = item.isSelected {
|
||||||
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, isSelected, .regular)
|
let sizeAndApply = selectableControlLayout(item.presentationData.theme.list.itemCheckColors.strokeColor, item.presentationData.theme.list.itemCheckColors.fillColor, item.presentationData.theme.list.itemCheckColors.foregroundColor, isSelected, .regular, nil)
|
||||||
selectableControlSizeAndApply = sizeAndApply
|
selectableControlSizeAndApply = sizeAndApply
|
||||||
editingOffset = sizeAndApply.0
|
editingOffset = sizeAndApply.0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,7 @@ final class AttachmentFileContext: AttachmentMediaPickerContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
|
func send(mode: AttachmentMediaPickerSendMode, attachmentMode: AttachmentMediaPickerAttachmentMode, parameters: ChatSendMessageActionSheetController.SendParameters?) {
|
||||||
self.controller?.mulitpleCompletion?(mode, .files, parameters)
|
self.controller?.mulitpleCompletion?(mode, .files, parameters, self.controller?.caption)
|
||||||
}
|
}
|
||||||
|
|
||||||
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
|
func schedule(parameters: ChatSendMessageActionSheetController.SendParameters?) {
|
||||||
|
|
@ -436,7 +436,7 @@ public class AttachmentFileControllerImpl: ItemListController, AttachmentFileCon
|
||||||
|
|
||||||
fileprivate var bottomEdgeColor: UIColor = .clear
|
fileprivate var bottomEdgeColor: UIColor = .clear
|
||||||
|
|
||||||
fileprivate var mulitpleCompletion: ((AttachmentMediaPickerSendMode, AttachmentMediaPickerAttachmentMode, ChatSendMessageActionSheetController.SendParameters?) -> Void)?
|
fileprivate var mulitpleCompletion: ((AttachmentMediaPickerSendMode, AttachmentMediaPickerAttachmentMode, ChatSendMessageActionSheetController.SendParameters?, NSAttributedString?) -> Void)?
|
||||||
|
|
||||||
var delayDisappear = false
|
var delayDisappear = false
|
||||||
|
|
||||||
|
|
@ -508,15 +508,19 @@ private struct AttachmentFileControllerState: Equatable {
|
||||||
var searching: Bool
|
var searching: Bool
|
||||||
var savedMusicExpanded: Bool
|
var savedMusicExpanded: Bool
|
||||||
var recentMusicExpanded: Bool
|
var recentMusicExpanded: Bool
|
||||||
var selectedMessageIds: Set<MessageId>?
|
var selectedMessageIds: [MessageId]?
|
||||||
var messageMap: [MessageId: EngineMessage]
|
var messageMap: [MessageId: EngineMessage]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func messageSelectionState(state: AttachmentFileControllerState, message: Message?) -> ChatHistoryMessageSelection {
|
private func messageSelectionState(state: AttachmentFileControllerState, message: Message?) -> ChatHistoryMessageSelection {
|
||||||
guard let message = message, let selectedMessageIds = state.selectedMessageIds else {
|
guard let message, let selectedMessageIds = state.selectedMessageIds else {
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
return .selectable(selected: selectedMessageIds.contains(message.id))
|
if let index = selectedMessageIds.firstIndex(where: { $0 == message.id }) {
|
||||||
|
return .selectable(selected: true, num: index)
|
||||||
|
} else {
|
||||||
|
return .selectable(selected: false, num: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AttachmentFileControllerMode {
|
public enum AttachmentFileControllerMode {
|
||||||
|
|
@ -551,7 +555,7 @@ public func makeAttachmentFileControllerImpl(
|
||||||
presentGallery: @escaping () -> Void,
|
presentGallery: @escaping () -> Void,
|
||||||
presentFiles: @escaping () -> Void,
|
presentFiles: @escaping () -> Void,
|
||||||
presentDocumentScanner: (() -> Void)?,
|
presentDocumentScanner: (() -> Void)?,
|
||||||
send: @escaping ([AnyMediaReference]) -> Void
|
send: @escaping ([AnyMediaReference], Bool, Int32?, NSAttributedString?) -> Void
|
||||||
) -> AttachmentFileController {
|
) -> AttachmentFileController {
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
|
|
@ -609,7 +613,7 @@ public func makeAttachmentFileControllerImpl(
|
||||||
send: { message in
|
send: { message in
|
||||||
if message.id.namespace == Namespaces.Message.Local {
|
if message.id.namespace == Namespaces.Message.Local {
|
||||||
if let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile {
|
if let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile {
|
||||||
send([.standalone(media: file)])
|
send([.standalone(media: file)], false, nil, nil)
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -625,7 +629,7 @@ public func makeAttachmentFileControllerImpl(
|
||||||
}
|
}
|
||||||
|> deliverOnMainQueue).startStandalone(next: { messages in
|
|> deliverOnMainQueue).startStandalone(next: { messages in
|
||||||
if let message = messages.first, let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile {
|
if let message = messages.first, let file = message.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile {
|
||||||
send([.message(message: MessageReference(message), media: file)])
|
send([.message(message: MessageReference(message), media: file)], false, nil, nil)
|
||||||
}
|
}
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
})
|
})
|
||||||
|
|
@ -647,9 +651,9 @@ public func makeAttachmentFileControllerImpl(
|
||||||
}
|
}
|
||||||
let messageId = message.id
|
let messageId = message.id
|
||||||
if selectedMessageIds.contains(messageId) {
|
if selectedMessageIds.contains(messageId) {
|
||||||
selectedMessageIds.remove(messageId)
|
selectedMessageIds.removeAll(where: { $0 == messageId })
|
||||||
} else {
|
} else {
|
||||||
selectedMessageIds.insert(messageId)
|
selectedMessageIds.append(messageId)
|
||||||
}
|
}
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
updatedState.selectedMessageIds = selectedMessageIds
|
updatedState.selectedMessageIds = selectedMessageIds
|
||||||
|
|
@ -665,9 +669,9 @@ public func makeAttachmentFileControllerImpl(
|
||||||
}
|
}
|
||||||
for messageId in messageIds {
|
for messageId in messageIds {
|
||||||
if value {
|
if value {
|
||||||
selectedMessageIds.insert(messageId)
|
selectedMessageIds.append(messageId)
|
||||||
} else {
|
} else {
|
||||||
selectedMessageIds.remove(messageId)
|
selectedMessageIds.removeAll(where: { $0 == messageId })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
|
|
@ -701,8 +705,8 @@ public func makeAttachmentFileControllerImpl(
|
||||||
c?.dismiss(completion: {})
|
c?.dismiss(completion: {})
|
||||||
updateState { state in
|
updateState { state in
|
||||||
var updatedState = state
|
var updatedState = state
|
||||||
var selectedMessageIds = updatedState.selectedMessageIds ?? Set()
|
var selectedMessageIds = updatedState.selectedMessageIds ?? []
|
||||||
selectedMessageIds.insert(message.id)
|
selectedMessageIds.append(message.id)
|
||||||
updatedState.selectedMessageIds = selectedMessageIds
|
updatedState.selectedMessageIds = selectedMessageIds
|
||||||
updatedState.messageMap[message.id] = message
|
updatedState.messageMap[message.id] = message
|
||||||
updateSelectionCountImpl?(selectedMessageIds.count)
|
updateSelectionCountImpl?(selectedMessageIds.count)
|
||||||
|
|
@ -932,7 +936,7 @@ public func makeAttachmentFileControllerImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = AttachmentFileControllerImpl(context: context, state: signal, hideNavigationBarBackground: true)
|
let controller = AttachmentFileControllerImpl(context: context, state: signal, hideNavigationBarBackground: true)
|
||||||
controller.mulitpleCompletion = { _, _, _ in
|
controller.mulitpleCompletion = { sendMode, _, _, caption in
|
||||||
let _ = stateValue.with({ state in
|
let _ = stateValue.with({ state in
|
||||||
if let selectedMessageIds = state.selectedMessageIds {
|
if let selectedMessageIds = state.selectedMessageIds {
|
||||||
var mediaReferences: [AnyMediaReference] = []
|
var mediaReferences: [AnyMediaReference] = []
|
||||||
|
|
@ -941,7 +945,7 @@ public func makeAttachmentFileControllerImpl(
|
||||||
mediaReferences.append(.standalone(media: file))
|
mediaReferences.append(.standalone(media: file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
send(mediaReferences)
|
send(mediaReferences, sendMode == .silently, nil, caption)
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1026,7 +1030,7 @@ public func storyAudioPickerController(
|
||||||
let filePickerController = makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, mode: .audio(story: true), bannedSendMedia: nil, presentGallery: {}, presentFiles: {
|
let filePickerController = makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, mode: .audio(story: true), bannedSendMedia: nil, presentGallery: {}, presentFiles: {
|
||||||
selectFromFiles()
|
selectFromFiles()
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
}, presentDocumentScanner: nil, send: { files in
|
}, presentDocumentScanner: nil, send: { files, _, _, _ in
|
||||||
completion(files.first!)
|
completion(files.first!)
|
||||||
dismissImpl?()
|
dismissImpl?()
|
||||||
}) as! AttachmentFileControllerImpl
|
}) as! AttachmentFileControllerImpl
|
||||||
|
|
|
||||||
|
|
@ -348,16 +348,30 @@ struct AttachmentFileSearchContainerTransition {
|
||||||
let isSearching: Bool
|
let isSearching: Bool
|
||||||
let isEmpty: Bool
|
let isEmpty: Bool
|
||||||
let query: String
|
let query: String
|
||||||
|
let crossfade: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attachmentFileSearchContainerPreparedRecentTransition(from fromEntries: [AttachmentFileSearchEntry], to toEntries: [AttachmentFileSearchEntry], isSearching: Bool, isEmpty: Bool, query: String, context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: AttachmentFileSearchContainerInteraction, mode: AttachmentFileControllerMode) -> AttachmentFileSearchContainerTransition {
|
private func attachmentFileSearchContainerPreparedRecentTransition(
|
||||||
|
from fromEntries: [AttachmentFileSearchEntry],
|
||||||
|
to toEntries: [AttachmentFileSearchEntry],
|
||||||
|
isSearching: Bool,
|
||||||
|
isEmpty: Bool,
|
||||||
|
query: String,
|
||||||
|
context: AccountContext,
|
||||||
|
presentationData: PresentationData,
|
||||||
|
nameSortOrder: PresentationPersonNameOrder,
|
||||||
|
nameDisplayOrder: PresentationPersonNameOrder,
|
||||||
|
interaction: AttachmentFileSearchContainerInteraction,
|
||||||
|
mode: AttachmentFileControllerMode,
|
||||||
|
crossfade: Bool
|
||||||
|
) -> AttachmentFileSearchContainerTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction, mode: mode), directionHint: nil) }
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction, mode: mode), directionHint: nil) }
|
||||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction, mode: mode), directionHint: nil) }
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction, mode: mode), directionHint: nil) }
|
||||||
|
|
||||||
return AttachmentFileSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching, isEmpty: isEmpty, query: query)
|
return AttachmentFileSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching, isEmpty: isEmpty, query: query, crossfade: crossfade)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -553,7 +567,9 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if let data = context.currentAppConfiguration.with({ $0 }).data, let searchBot = data["music_search_username"] as? String, !searchBot.isEmpty {
|
let trimmedQuery = query.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
|
||||||
|
if let data = context.currentAppConfiguration.with({ $0 }).data, let searchBot = data["music_search_username"] as? String, !searchBot.isEmpty, trimmedQuery.count >= 3 {
|
||||||
globalMusic = .single(nil)
|
globalMusic = .single(nil)
|
||||||
|> then(
|
|> then(
|
||||||
context.engine.peers.resolvePeerByName(name: searchBot, referrer: nil)
|
context.engine.peers.resolvePeerByName(name: searchBot, referrer: nil)
|
||||||
|
|
@ -567,7 +583,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
|
||||||
guard let peer = peer else {
|
guard let peer = peer else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
return context.engine.messages.requestChatContextResults(botId: peer.id, peerId: context.account.peerId, query: query, offset: "")
|
return context.engine.messages.requestChatContextResults(botId: peer.id, peerId: context.account.peerId, query: trimmedQuery, offset: "")
|
||||||
|> map { results -> ChatContextResultCollection? in
|
|> map { results -> ChatContextResultCollection? in
|
||||||
return results?.results
|
return results?.results
|
||||||
}
|
}
|
||||||
|
|
@ -673,13 +689,27 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
|
||||||
}
|
}
|
||||||
|
|
||||||
let previousSearchItems = Atomic<[AttachmentFileSearchEntry]?>(value: nil)
|
let previousSearchItems = Atomic<[AttachmentFileSearchEntry]?>(value: nil)
|
||||||
|
let previousHadGlobalItems = Atomic<Bool>(value: false)
|
||||||
self.searchDisposable.set((combineLatest(searchQuery, foundItems, self.presentationDataPromise.get())
|
self.searchDisposable.set((combineLatest(searchQuery, foundItems, self.presentationDataPromise.get())
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] query, entries, presentationData in
|
|> deliverOnMainQueue).startStrict(next: { [weak self] query, entries, presentationData in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let previousEntries = previousSearchItems.swap(entries)
|
let previousEntries = previousSearchItems.swap(entries)
|
||||||
updateActivity(false)
|
updateActivity(false)
|
||||||
let firstTime = previousEntries == nil
|
let firstTime = previousEntries == nil
|
||||||
let transition = attachmentFileSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, isEmpty: entries?.isEmpty ?? false, query: query ?? "", context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction, mode: mode)
|
|
||||||
|
var hasGlobalItems = false
|
||||||
|
if let entries {
|
||||||
|
for entry in entries {
|
||||||
|
if case let .header(_, section) = entry, section == 2 {
|
||||||
|
hasGlobalItems = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let hadGlobalItems = previousHadGlobalItems.swap(hasGlobalItems)
|
||||||
|
|
||||||
|
let crossfade = hadGlobalItems != hasGlobalItems
|
||||||
|
|
||||||
|
let transition = attachmentFileSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, isEmpty: entries?.isEmpty ?? false, query: query ?? "", context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction, mode: mode, crossfade: crossfade)
|
||||||
strongSelf.enqueueTransition(transition, firstTime: firstTime)
|
strongSelf.enqueueTransition(transition, firstTime: firstTime)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
@ -739,6 +769,10 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
|
||||||
|
|
||||||
//options.insert(.AnimateInsertion)
|
//options.insert(.AnimateInsertion)
|
||||||
|
|
||||||
|
if transition.crossfade {
|
||||||
|
options.insert(.AnimateCrossfade)
|
||||||
|
}
|
||||||
|
|
||||||
let isSearching = transition.isSearching
|
let isSearching = transition.isSearching
|
||||||
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
|
self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|
|
||||||
|
|
@ -2183,7 +2183,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||||
switch selection {
|
switch selection {
|
||||||
case .none:
|
case .none:
|
||||||
break
|
break
|
||||||
case let .selectable(selected):
|
case let .selectable(selected, _):
|
||||||
itemSelection = selected
|
itemSelection = selected
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ public func presentPollAttachmentScreen(
|
||||||
//TODO
|
//TODO
|
||||||
},
|
},
|
||||||
presentDocumentScanner: nil,
|
presentDocumentScanner: nil,
|
||||||
send: { mediaReferences in
|
send: { mediaReferences, _, _, _ in
|
||||||
completion(mediaReferences.first!)
|
completion(mediaReferences.first!)
|
||||||
}
|
}
|
||||||
) as! AttachmentFileControllerImpl
|
) as! AttachmentFileControllerImpl
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ swift_library(
|
||||||
"//submodules/UIKitRuntimeUtils",
|
"//submodules/UIKitRuntimeUtils",
|
||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
"//submodules/TelegramUI/Components/LensTransition",
|
"//submodules/TelegramUI/Components/LensTransition",
|
||||||
|
"//submodules/Components/BalancedTextComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import LottieComponent
|
||||||
import TextNodeWithEntities
|
import TextNodeWithEntities
|
||||||
import ContextUI
|
import ContextUI
|
||||||
import LensTransition
|
import LensTransition
|
||||||
|
import BalancedTextComponent
|
||||||
|
|
||||||
public protocol ContextControllerActionsListItemNode: ASDisplayNode {
|
public protocol ContextControllerActionsListItemNode: ASDisplayNode {
|
||||||
func update(presentationData: PresentationData, constrainedSize: CGSize) -> (minSize: CGSize, apply: (_ size: CGSize, _ transition: ContainedViewLayoutTransition) -> Void)
|
func update(presentationData: PresentationData, constrainedSize: CGSize) -> (minSize: CGSize, apply: (_ size: CGSize, _ transition: ContainedViewLayoutTransition) -> Void)
|
||||||
|
|
@ -39,6 +40,7 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||||
private var item: ContextMenuActionItem
|
private var item: ContextMenuActionItem
|
||||||
|
|
||||||
private let titleLabelNode: ImmediateTextNodeWithEntities
|
private let titleLabelNode: ImmediateTextNodeWithEntities
|
||||||
|
private let balancedTitleLabel = ComponentView<Empty>()
|
||||||
private let subtitleNode: ImmediateTextNode
|
private let subtitleNode: ImmediateTextNode
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
private let additionalIconNode: ASImageNode
|
private let additionalIconNode: ASImageNode
|
||||||
|
|
@ -282,7 +284,13 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||||
titleColor = presentationData.theme.contextMenu.primaryColor.withMultipliedAlpha(0.4)
|
titleColor = presentationData.theme.contextMenu.primaryColor.withMultipliedAlpha(0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var balanceTitleAttributedText: NSAttributedString?
|
||||||
if self.item.parseMarkdown || !self.item.entities.isEmpty {
|
if self.item.parseMarkdown || !self.item.entities.isEmpty {
|
||||||
|
var balancedTextLayout = false
|
||||||
|
if self.item.parseMarkdown, case .twoLinesMax = self.item.textLayout {
|
||||||
|
balancedTextLayout = true
|
||||||
|
}
|
||||||
|
|
||||||
let attributedText: NSAttributedString
|
let attributedText: NSAttributedString
|
||||||
if !self.item.entities.isEmpty {
|
if !self.item.entities.isEmpty {
|
||||||
let inputStateText = ChatTextInputStateText(text: self.item.text, attributes: self.item.entities.compactMap { entity -> ChatTextInputStateTextAttribute? in
|
let inputStateText = ChatTextInputStateText(text: self.item.text, attributes: self.item.entities.compactMap { entity -> ChatTextInputStateTextAttribute? in
|
||||||
|
|
@ -324,18 +332,25 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
self.titleLabelNode.attributedText = attributedText
|
|
||||||
self.titleLabelNode.linkHighlightColor = presentationData.theme.list.itemAccentColor.withMultipliedAlpha(0.5)
|
if self.item.entities.isEmpty && balancedTextLayout {
|
||||||
self.titleLabelNode.highlightAttributeAction = { attributes in
|
self.titleLabelNode.isHidden = true
|
||||||
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
balanceTitleAttributedText = attributedText
|
||||||
return NSAttributedString.Key(rawValue: "URL")
|
} else {
|
||||||
} else {
|
self.titleLabelNode.isHidden = false
|
||||||
return nil
|
self.titleLabelNode.attributedText = attributedText
|
||||||
|
self.titleLabelNode.linkHighlightColor = presentationData.theme.list.itemAccentColor.withMultipliedAlpha(0.5)
|
||||||
|
self.titleLabelNode.highlightAttributeAction = { attributes in
|
||||||
|
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||||
|
return NSAttributedString.Key(rawValue: "URL")
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
self.titleLabelNode.tapAttributeAction = { [weak item] attributes, _ in
|
||||||
self.titleLabelNode.tapAttributeAction = { [weak item] attributes, _ in
|
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
||||||
if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] {
|
item?.textLinkAction()
|
||||||
item?.textLinkAction()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -506,7 +521,22 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||||
|
|
||||||
maxTextWidth = max(1.0, maxTextWidth)
|
maxTextWidth = max(1.0, maxTextWidth)
|
||||||
|
|
||||||
let titleSize = self.titleLabelNode.updateLayout(CGSize(width: maxTextWidth, height: 1000.0))
|
let titleSize: CGSize
|
||||||
|
if let balanceTitleAttributedText {
|
||||||
|
titleSize = self.balancedTitleLabel.update(
|
||||||
|
transition: .immediate,
|
||||||
|
component: AnyComponent(
|
||||||
|
BalancedTextComponent(
|
||||||
|
text: .plain(balanceTitleAttributedText),
|
||||||
|
maximumNumberOfLines: 2
|
||||||
|
)
|
||||||
|
),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: maxTextWidth, height: 1000.0)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
titleSize = self.titleLabelNode.updateLayout(CGSize(width: maxTextWidth, height: 1000.0))
|
||||||
|
}
|
||||||
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: maxTextWidth, height: 1000.0))
|
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: maxTextWidth, height: 1000.0))
|
||||||
|
|
||||||
var minSize = CGSize()
|
var minSize = CGSize()
|
||||||
|
|
@ -549,7 +579,16 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||||
subtitleFrame.origin.x = titleFrame.minX
|
subtitleFrame.origin.x = titleFrame.minX
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrameAdditive(node: self.titleLabelNode, frame: titleFrame)
|
if let _ = balanceTitleAttributedText {
|
||||||
|
if let balancedTitleLabelView = self.balancedTitleLabel.view {
|
||||||
|
if balancedTitleLabelView.superview == nil {
|
||||||
|
self.view.addSubview(balancedTitleLabelView)
|
||||||
|
}
|
||||||
|
transition.updateFrameAdditive(view: balancedTitleLabelView, frame: titleFrame)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
transition.updateFrameAdditive(node: self.titleLabelNode, frame: titleFrame)
|
||||||
|
}
|
||||||
transition.updateFrameAdditive(node: self.subtitleNode, frame: subtitleFrame)
|
transition.updateFrameAdditive(node: self.subtitleNode, frame: subtitleFrame)
|
||||||
|
|
||||||
if let badgeIconNode = self.badgeIconNode, let iconSize = badgeIconNode.image?.size {
|
if let badgeIconNode = self.badgeIconNode, let iconSize = badgeIconNode.image?.size {
|
||||||
|
|
|
||||||
|
|
@ -532,7 +532,7 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let item = self.item, let messageItem = self.messageItem, let itemNode = itemNode as? ListMessageFileItemNode {
|
if let item = self.item, let messageItem = self.messageItem, let itemNode = itemNode as? ListMessageFileItemNode {
|
||||||
if case let .selectable(selected) = messageItem.selection {
|
if case let .selectable(selected, _) = messageItem.selection {
|
||||||
self.interaction?.toggleMessagesSelection([item.message.id], !selected)
|
self.interaction?.toggleMessagesSelection([item.message.id], !selected)
|
||||||
} else {
|
} else {
|
||||||
itemNode.activateMedia()
|
itemNode.activateMedia()
|
||||||
|
|
@ -560,7 +560,7 @@ private final class ItemView: UIView, SparseItemGridView {
|
||||||
interaction: interaction,
|
interaction: interaction,
|
||||||
message: item.message,
|
message: item.message,
|
||||||
selection: isSelected.flatMap { isSelected in
|
selection: isSelected.flatMap { isSelected in
|
||||||
return .selectable(selected: isSelected)
|
return .selectable(selected: isSelected, num: nil)
|
||||||
} ?? .none,
|
} ?? .none,
|
||||||
displayHeader: false
|
displayHeader: false
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1948,7 +1948,7 @@ final class StoryItemSetContainerSendMessage: @unchecked(Sendable) {
|
||||||
}
|
}
|
||||||
attachmentController?.dismiss(animated: true)
|
attachmentController?.dismiss(animated: true)
|
||||||
self.presentICloudFileGallery(view: view, peer: peer, replyMessageId: nil, replyToStoryId: focusedStoryId)
|
self.presentICloudFileGallery(view: view, peer: peer, replyMessageId: nil, replyToStoryId: focusedStoryId)
|
||||||
}, presentDocumentScanner: nil, send: { [weak view] mediaReferences in
|
}, presentDocumentScanner: nil, send: { [weak view] mediaReferences, _, _, _ in
|
||||||
guard let view, let component = view.component else {
|
guard let view, let component = view.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import ChatControllerInteraction
|
||||||
import Pasteboard
|
import Pasteboard
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import AvatarNode
|
||||||
|
|
||||||
private enum OptionsId: Hashable {
|
private enum OptionsId: Hashable {
|
||||||
case item
|
case item
|
||||||
|
|
@ -37,8 +38,16 @@ extension ChatControllerImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = (contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: self.presentationInterfaceState, context: self.context, messages: [message], controllerInteraction: self.controllerInteraction, selectAll: false, interfaceInteraction: self.interfaceInteraction, messageNode: params.messageNode as? ChatMessageItemView)
|
var addedByPeer: Signal<EnginePeer?, NoError> = .single(nil)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] actions in
|
if let peerId = pollOption.addedBy {
|
||||||
|
addedByPeer = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = combineLatest(
|
||||||
|
queue: Queue.mainQueue(),
|
||||||
|
contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: self.presentationInterfaceState, context: self.context, messages: [message], controllerInteraction: self.controllerInteraction, selectAll: false, interfaceInteraction: self.interfaceInteraction, messageNode: params.messageNode as? ChatMessageItemView),
|
||||||
|
addedByPeer
|
||||||
|
).start(next: { [weak self] actions, addedByPeer in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +155,7 @@ extension ChatControllerImpl {
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pollOption.date != nil {
|
if let addedByPeer, let date = pollOption.date {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
items.append(.action(ContextMenuActionItem(text: "Remove", textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] _, f in
|
items.append(.action(ContextMenuActionItem(text: "Remove", textColor: .destructive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
|
@ -156,6 +165,49 @@ extension ChatControllerImpl {
|
||||||
}
|
}
|
||||||
let _ = self.context.engine.messages.deletePollOption(messageId: message.id, opaqueIdentifier: pollOption.opaqueIdentifier).start()
|
let _ = self.context.engine.messages.deletePollOption(messageId: message.id, opaqueIdentifier: pollOption.opaqueIdentifier).start()
|
||||||
})))
|
})))
|
||||||
|
|
||||||
|
items.append(.separator)
|
||||||
|
|
||||||
|
let peerName = "**\(addedByPeer.compactDisplayTitle)**"
|
||||||
|
let dateText = humanReadableStringForTimestamp(strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, timestamp: date, alwaysShowTime: true, allowYesterday: true, format: HumanReadableStringFormat(
|
||||||
|
dateFormatString: { value in
|
||||||
|
if addedByPeer.id == self.context.account.peerId {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestampYou_Date(value).string, ranges: [])
|
||||||
|
} else {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestamp_Date(peerName, value).string, ranges: [])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tomorrowFormatString: { value in
|
||||||
|
if addedByPeer.id == self.context.account.peerId {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestampYou_TodayAt(value).string, ranges: [])
|
||||||
|
} else {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestamp_TodayAt(peerName, value).string, ranges: [])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
todayFormatString: { value in
|
||||||
|
if addedByPeer.id == self.context.account.peerId {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestampYou_TodayAt(value).string, ranges: [])
|
||||||
|
} else {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestamp_TodayAt(peerName, value).string, ranges: [])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yesterdayFormatString: { value in
|
||||||
|
if addedByPeer.id == self.context.account.peerId {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestampYou_YesterdayAt(value).string, ranges: [])
|
||||||
|
} else {
|
||||||
|
return PresentationStrings.FormattedString(string: self.presentationData.strings.Chat_PolOptionAddedTimestamp_YesterdayAt(peerName, value).string, ranges: [])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)).string
|
||||||
|
|
||||||
|
let avatarSize = CGSize(width: 24.0, height: 24.0)
|
||||||
|
items.append(.action(ContextMenuActionItem(text: dateText, textFont: .small, parseMarkdown: true, icon: { _ in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: self.context.account, peer: addedByPeer, size: avatarSize)), action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openPeer(peer: addedByPeer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.canReadHistory.set(false)
|
self.canReadHistory.set(false)
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,7 @@ extension ChatControllerImpl {
|
||||||
self?.presentICloudFileGallery()
|
self?.presentICloudFileGallery()
|
||||||
}, presentDocumentScanner: { [weak self] in
|
}, presentDocumentScanner: { [weak self] in
|
||||||
self?.presentDocumentScanner()
|
self?.presentDocumentScanner()
|
||||||
}, send: { [weak self] mediaReferences in
|
}, send: { [weak self] mediaReferences, silentPosting, scheduleTime, caption in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -390,9 +390,26 @@ extension ChatControllerImpl {
|
||||||
if mediaReferences.count > 1 {
|
if mediaReferences.count > 1 {
|
||||||
groupingKey = Int64.random(in: .min ..< .max)
|
groupingKey = Int64.random(in: .min ..< .max)
|
||||||
}
|
}
|
||||||
for mediaReference in mediaReferences {
|
|
||||||
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: groupingKey, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
var attributes: [MessageAttribute] = []
|
||||||
|
var text = ""
|
||||||
|
if let caption {
|
||||||
|
text = caption.string
|
||||||
|
let entities = generateTextEntities(text, enabledTypes: .all, currentEntities: generateChatInputTextEntities(caption))
|
||||||
|
if !entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: entities))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for mediaReference in mediaReferences {
|
||||||
|
if messages.count == 10 {
|
||||||
|
groupingKey = Int64.random(in: .min ..< .max)
|
||||||
|
}
|
||||||
|
let isLast = mediaReference == mediaReferences.last
|
||||||
|
|
||||||
|
messages.append(.message(text: isLast ? text : "", attributes: isLast ? attributes : [], inlineStickers: [:], mediaReference: mediaReference, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: groupingKey, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||||
|
}
|
||||||
|
messages = self.transformEnqueueMessages(messages, silentPosting: silentPosting, scheduleTime: scheduleTime, repeatPeriod: nil, postpone: false)
|
||||||
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||||
self?.sendMessages(messages, media: true, postpone: postpone)
|
self?.sendMessages(messages, media: true, postpone: postpone)
|
||||||
})
|
})
|
||||||
|
|
@ -414,7 +431,7 @@ extension ChatControllerImpl {
|
||||||
}, presentFiles: { [weak self, weak attachmentController] in
|
}, presentFiles: { [weak self, weak attachmentController] in
|
||||||
attachmentController?.dismiss(animated: true)
|
attachmentController?.dismiss(animated: true)
|
||||||
self?.presentICloudFileGallery(documentTypes: ["public.mp3", "public.mpeg-4-audio", "public.aac-audio", "org.xiph.flac"])
|
self?.presentICloudFileGallery(documentTypes: ["public.mp3", "public.mpeg-4-audio", "public.aac-audio", "org.xiph.flac"])
|
||||||
}, presentDocumentScanner: nil, send: { [weak self] mediaReferences in
|
}, presentDocumentScanner: nil, send: { [weak self] mediaReferences, silentPosting, scheduleTime, caption in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -423,9 +440,26 @@ extension ChatControllerImpl {
|
||||||
if mediaReferences.count > 1 {
|
if mediaReferences.count > 1 {
|
||||||
groupingKey = Int64.random(in: .min ..< .max)
|
groupingKey = Int64.random(in: .min ..< .max)
|
||||||
}
|
}
|
||||||
for mediaReference in mediaReferences {
|
|
||||||
messages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: groupingKey, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
var attributes: [MessageAttribute] = []
|
||||||
|
var text = ""
|
||||||
|
if let caption {
|
||||||
|
text = caption.string
|
||||||
|
let entities = generateTextEntities(text, enabledTypes: .all, currentEntities: generateChatInputTextEntities(caption))
|
||||||
|
if !entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: entities))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for mediaReference in mediaReferences {
|
||||||
|
if messages.count == 10 {
|
||||||
|
groupingKey = Int64.random(in: .min ..< .max)
|
||||||
|
}
|
||||||
|
let isLast = mediaReference == mediaReferences.last
|
||||||
|
|
||||||
|
messages.append(.message(text: isLast ? text : "", attributes: isLast ? attributes : [], inlineStickers: [:], mediaReference: mediaReference, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: groupingKey, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||||
|
}
|
||||||
|
messages = self.transformEnqueueMessages(messages, silentPosting: silentPosting, scheduleTime: scheduleTime, repeatPeriod: nil, postpone: false)
|
||||||
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
self.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||||
self?.sendMessages(messages, media: true, postpone: postpone)
|
self?.sendMessages(messages, media: true, postpone: postpone)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ func chatHistoryEntriesForView(
|
||||||
if let messageGroupingKey = message.groupingKey {
|
if let messageGroupingKey = message.groupingKey {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
if let selectedMessages = selectedMessages {
|
if let selectedMessages = selectedMessages {
|
||||||
selection = .selectable(selected: selectedMessages.contains(message.id))
|
selection = .selectable(selected: selectedMessages.contains(message.id), num: nil)
|
||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
|
|
@ -293,7 +293,7 @@ func chatHistoryEntriesForView(
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
if let selectedMessages = selectedMessages {
|
if let selectedMessages = selectedMessages {
|
||||||
selection = .selectable(selected: selectedMessages.contains(message.id))
|
selection = .selectable(selected: selectedMessages.contains(message.id), num: nil)
|
||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +308,7 @@ func chatHistoryEntriesForView(
|
||||||
} else {
|
} else {
|
||||||
let selection: ChatHistoryMessageSelection
|
let selection: ChatHistoryMessageSelection
|
||||||
if let selectedMessages = selectedMessages {
|
if let selectedMessages = selectedMessages {
|
||||||
selection = .selectable(selected: selectedMessages.contains(message.id))
|
selection = .selectable(selected: selectedMessages.contains(message.id), num: nil)
|
||||||
} else {
|
} else {
|
||||||
selection = .none
|
selection = .none
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2750,7 +2750,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, audio: Bool, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, presentDocumentScanner: (() -> Void)?, send: @escaping ([AnyMediaReference]) -> Void) -> AttachmentFileController {
|
public func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, audio: Bool, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, presentDocumentScanner: (() -> Void)?, send: @escaping ([AnyMediaReference], Bool, Int32?, NSAttributedString?) -> Void) -> AttachmentFileController {
|
||||||
return makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, mode: audio ? .audio(story: false) : .recent, bannedSendMedia: bannedSendMedia, presentGallery: presentGallery, presentFiles: presentFiles, presentDocumentScanner: presentDocumentScanner, send: send)
|
return makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, mode: audio ? .audio(story: false) : .recent, bannedSendMedia: bannedSendMedia, presentGallery: presentGallery, presentFiles: presentFiles, presentDocumentScanner: presentDocumentScanner, send: send)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue