mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 17:43:18 +00:00
Story improvements
This commit is contained in:
parent
060bc61011
commit
1c2f989fbd
@ -738,6 +738,9 @@ public protocol AppLockContext: AnyObject {
|
|||||||
public protocol RecentSessionsController: AnyObject {
|
public protocol RecentSessionsController: AnyObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public protocol AttachmentFileController: AnyObject {
|
||||||
|
}
|
||||||
|
|
||||||
public protocol SharedAccountContext: AnyObject {
|
public protocol SharedAccountContext: AnyObject {
|
||||||
var sharedContainerPath: String { get }
|
var sharedContainerPath: String { get }
|
||||||
var basePath: String { get }
|
var basePath: String { get }
|
||||||
@ -805,6 +808,8 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
func makePrivacyAndSecurityController(context: AccountContext) -> ViewController
|
||||||
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>)?, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController
|
||||||
|
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
||||||
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
func navigateToChatController(_ params: NavigateToChatControllerParams)
|
||||||
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
func navigateToForumChannel(context: AccountContext, peerId: EnginePeer.Id, navigationController: NavigationController)
|
||||||
func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal<Never, NoError>
|
func navigateToForumThread(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64, messageId: EngineMessage.Id?, navigationController: NavigationController, activateInput: ChatControllerActivateInput?, keepStack: NavigateToChatKeepStack) -> Signal<Never, NoError>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ public protocol ContactSelectionController: ViewController {
|
|||||||
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?)?, NoError> { get }
|
var result: Signal<([ContactListPeer], ContactListAction, Bool, Int32?, NSAttributedString?)?, NoError> { get }
|
||||||
var displayProgress: Bool { get set }
|
var displayProgress: Bool { get set }
|
||||||
var dismissed: (() -> Void)? { get set }
|
var dismissed: (() -> Void)? { get set }
|
||||||
|
var presentScheduleTimePicker: (@escaping (Int32) -> Void) -> Void { get set }
|
||||||
|
|
||||||
func dismissSearch()
|
func dismissSearch()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -463,6 +463,7 @@ public protocol PresentationGroupCall: AnyObject {
|
|||||||
public protocol PresentationCallManager: AnyObject {
|
public protocol PresentationCallManager: AnyObject {
|
||||||
var currentCallSignal: Signal<PresentationCall?, NoError> { get }
|
var currentCallSignal: Signal<PresentationCall?, NoError> { get }
|
||||||
var currentGroupCallSignal: Signal<PresentationGroupCall?, NoError> { get }
|
var currentGroupCallSignal: Signal<PresentationGroupCall?, NoError> { get }
|
||||||
|
var hasActiveCall: Bool { get }
|
||||||
|
|
||||||
func requestCall(context: AccountContext, peerId: EnginePeer.Id, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
|
func requestCall(context: AccountContext, peerId: EnginePeer.Id, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
|
||||||
func joinGroupCall(context: AccountContext, peerId: EnginePeer.Id, invite: String?, requestJoinAsPeerId: ((@escaping (EnginePeer.Id?) -> Void) -> Void)?, initialCall: EngineGroupCallDescription, endCurrentIfAny: Bool) -> JoinGroupCallManagerResult
|
func joinGroupCall(context: AccountContext, peerId: EnginePeer.Id, invite: String?, requestJoinAsPeerId: ((@escaping (EnginePeer.Id?) -> Void) -> Void)?, initialCall: EngineGroupCallDescription, endCurrentIfAny: Bool) -> JoinGroupCallManagerResult
|
||||||
|
|||||||
@ -84,6 +84,7 @@ public protocol AttachmentContainable: ViewController {
|
|||||||
var cancelPanGesture: () -> Void { get set }
|
var cancelPanGesture: () -> Void { get set }
|
||||||
var isContainerPanning: () -> Bool { get set }
|
var isContainerPanning: () -> Bool { get set }
|
||||||
var isContainerExpanded: () -> Bool { get set }
|
var isContainerExpanded: () -> Bool { get set }
|
||||||
|
var mediaPickerContext: AttachmentMediaPickerContext? { get }
|
||||||
|
|
||||||
func isContainerPanningUpdated(_ panning: Bool)
|
func isContainerPanningUpdated(_ panning: Bool)
|
||||||
|
|
||||||
|
|||||||
@ -611,6 +611,8 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let loginCodeRegex = try? NSRegularExpression(pattern: "[\\d\\-]{5,7}", options: [])
|
||||||
|
|
||||||
class ChatListItemNode: ItemListRevealOptionsItemNode {
|
class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
final class TopicItemNode: ASDisplayNode {
|
final class TopicItemNode: ASDisplayNode {
|
||||||
let topicTitleNode: TextNode
|
let topicTitleNode: TextNode
|
||||||
@ -1841,7 +1843,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor)
|
authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
let entities = (message._asMessage().textEntitiesAttribute?.entities ?? []).filter { entity in
|
var entities = (message._asMessage().textEntitiesAttribute?.entities ?? []).filter { entity in
|
||||||
switch entity.type {
|
switch entity.type {
|
||||||
case .Spoiler, .CustomEmoji:
|
case .Spoiler, .CustomEmoji:
|
||||||
return true
|
return true
|
||||||
@ -1851,6 +1853,18 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if message.author?.id.id == PeerId.Id._internalFromInt64Value(777000) {
|
||||||
|
if let loginCodeRegex {
|
||||||
|
let results = loginCodeRegex.matches(in: message.text, range: NSRange(message.text.startIndex..., in: message.text))
|
||||||
|
for result in results {
|
||||||
|
let spoilerRange: Range<Int> = result.range.location ..< (result.range.location + result.range.length)
|
||||||
|
if !entities.contains(where: { $0.range.overlaps(spoilerRange) }) {
|
||||||
|
entities.append(MessageTextEntity(range: spoilerRange, type: .Spoiler))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let messageString: NSAttributedString
|
let messageString: NSAttributedString
|
||||||
if !message.text.isEmpty && entities.count > 0 {
|
if !message.text.isEmpty && entities.count > 0 {
|
||||||
var messageText = message.text
|
var messageText = message.text
|
||||||
|
|||||||
22
submodules/ICloudResources/BUILD
Normal file
22
submodules/ICloudResources/BUILD
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "ICloudResources",
|
||||||
|
module_name = "ICloudResources",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/Postbox",
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/Pdf",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -63,17 +63,17 @@ public class ICloudFileResource: TelegramMediaResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ICloudFileDescription {
|
public struct ICloudFileDescription {
|
||||||
struct AudioMetadata {
|
public struct AudioMetadata {
|
||||||
let title: String?
|
public let title: String?
|
||||||
let performer: String?
|
public let performer: String?
|
||||||
let duration: Int
|
public let duration: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
let urlData: String
|
public let urlData: String
|
||||||
let fileName: String
|
public let fileName: String
|
||||||
let fileSize: Int
|
public let fileSize: Int
|
||||||
let audioMetadata: AudioMetadata?
|
public let audioMetadata: AudioMetadata?
|
||||||
}
|
}
|
||||||
|
|
||||||
private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? {
|
private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? {
|
||||||
@ -115,7 +115,7 @@ private func descriptionWithUrl(_ url: URL) -> ICloudFileDescription? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func iCloudFileDescription(_ url: URL) -> Signal<ICloudFileDescription?, NoError> {
|
public func iCloudFileDescription(_ url: URL) -> Signal<ICloudFileDescription?, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
var isRemote = false
|
var isRemote = false
|
||||||
var isCurrent = true
|
var isCurrent = true
|
||||||
@ -191,7 +191,7 @@ private final class ICloudFileResourceCopyItem: MediaResourceDataFetchCopyLocalI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
public func fetchICloudFileResource(resource: ICloudFileResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
subscriber.putNext(.reset)
|
subscriber.putNext(.reset)
|
||||||
|
|
||||||
@ -438,6 +438,10 @@ open class LegacyController: ViewController, PresentableController, AttachmentCo
|
|||||||
open var isContainerPanning: () -> Bool = { return false }
|
open var isContainerPanning: () -> Bool = { return false }
|
||||||
open var isContainerExpanded: () -> Bool = { return false }
|
open var isContainerExpanded: () -> Bool = { return false }
|
||||||
|
|
||||||
|
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
public init(presentation: LegacyControllerPresentation, theme: PresentationTheme? = nil, strings: PresentationStrings? = nil, initialLayout: ContainerViewLayout? = nil) {
|
public init(presentation: LegacyControllerPresentation, theme: PresentationTheme? = nil, strings: PresentationStrings? = nil, initialLayout: ContainerViewLayout? = nil) {
|
||||||
self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber))
|
self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber))
|
||||||
self.presentation = presentation
|
self.presentation = presentation
|
||||||
|
|||||||
@ -524,13 +524,13 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[784356159] = { return Api.MessageMedia.parse_messageMediaVenue($0) }
|
dict[784356159] = { return Api.MessageMedia.parse_messageMediaVenue($0) }
|
||||||
dict[-1557277184] = { return Api.MessageMedia.parse_messageMediaWebPage($0) }
|
dict[-1557277184] = { return Api.MessageMedia.parse_messageMediaWebPage($0) }
|
||||||
dict[-1938180548] = { return Api.MessagePeerReaction.parse_messagePeerReaction($0) }
|
dict[-1938180548] = { return Api.MessagePeerReaction.parse_messagePeerReaction($0) }
|
||||||
|
dict[-1228133028] = { return Api.MessagePeerVote.parse_messagePeerVote($0) }
|
||||||
|
dict[1959634180] = { return Api.MessagePeerVote.parse_messagePeerVoteInputOption($0) }
|
||||||
|
dict[1177089766] = { return Api.MessagePeerVote.parse_messagePeerVoteMultiple($0) }
|
||||||
dict[182649427] = { return Api.MessageRange.parse_messageRange($0) }
|
dict[182649427] = { return Api.MessageRange.parse_messageRange($0) }
|
||||||
dict[1328256121] = { return Api.MessageReactions.parse_messageReactions($0) }
|
dict[1328256121] = { return Api.MessageReactions.parse_messageReactions($0) }
|
||||||
dict[-2083123262] = { return Api.MessageReplies.parse_messageReplies($0) }
|
dict[-2083123262] = { return Api.MessageReplies.parse_messageReplies($0) }
|
||||||
dict[-1495959709] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
|
dict[-1495959709] = { return Api.MessageReplyHeader.parse_messageReplyHeader($0) }
|
||||||
dict[886196148] = { return Api.MessageUserVote.parse_messageUserVote($0) }
|
|
||||||
dict[1017491692] = { return Api.MessageUserVote.parse_messageUserVoteInputOption($0) }
|
|
||||||
dict[-1973033641] = { return Api.MessageUserVote.parse_messageUserVoteMultiple($0) }
|
|
||||||
dict[1163625789] = { return Api.MessageViews.parse_messageViews($0) }
|
dict[1163625789] = { return Api.MessageViews.parse_messageViews($0) }
|
||||||
dict[975236280] = { return Api.MessagesFilter.parse_inputMessagesFilterChatPhotos($0) }
|
dict[975236280] = { return Api.MessagesFilter.parse_inputMessagesFilterChatPhotos($0) }
|
||||||
dict[-530392189] = { return Api.MessagesFilter.parse_inputMessagesFilterContacts($0) }
|
dict[-530392189] = { return Api.MessagesFilter.parse_inputMessagesFilterContacts($0) }
|
||||||
@ -635,7 +635,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-2032041631] = { return Api.Poll.parse_poll($0) }
|
dict[-2032041631] = { return Api.Poll.parse_poll($0) }
|
||||||
dict[1823064809] = { return Api.PollAnswer.parse_pollAnswer($0) }
|
dict[1823064809] = { return Api.PollAnswer.parse_pollAnswer($0) }
|
||||||
dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) }
|
dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) }
|
||||||
dict[-591909213] = { return Api.PollResults.parse_pollResults($0) }
|
dict[2061444128] = { return Api.PollResults.parse_pollResults($0) }
|
||||||
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
||||||
dict[512535275] = { return Api.PostAddress.parse_postAddress($0) }
|
dict[512535275] = { return Api.PostAddress.parse_postAddress($0) }
|
||||||
dict[1958953753] = { return Api.PremiumGiftOption.parse_premiumGiftOption($0) }
|
dict[1958953753] = { return Api.PremiumGiftOption.parse_premiumGiftOption($0) }
|
||||||
@ -856,7 +856,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[1517529484] = { return Api.Update.parse_updateMessageExtendedMedia($0) }
|
dict[1517529484] = { return Api.Update.parse_updateMessageExtendedMedia($0) }
|
||||||
dict[1318109142] = { return Api.Update.parse_updateMessageID($0) }
|
dict[1318109142] = { return Api.Update.parse_updateMessageID($0) }
|
||||||
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
||||||
dict[274961865] = { return Api.Update.parse_updateMessagePollVote($0) }
|
dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) }
|
||||||
dict[1578843320] = { return Api.Update.parse_updateMessageReactions($0) }
|
dict[1578843320] = { return Api.Update.parse_updateMessageReactions($0) }
|
||||||
dict[-2030252155] = { return Api.Update.parse_updateMoveStickerSetToTop($0) }
|
dict[-2030252155] = { return Api.Update.parse_updateMoveStickerSetToTop($0) }
|
||||||
dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) }
|
dict[1656358105] = { return Api.Update.parse_updateNewChannelMessage($0) }
|
||||||
@ -1108,7 +1108,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
|
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
|
||||||
dict[-1821037486] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) }
|
dict[-1821037486] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) }
|
||||||
dict[870003448] = { return Api.messages.TranslatedText.parse_translateResult($0) }
|
dict[870003448] = { return Api.messages.TranslatedText.parse_translateResult($0) }
|
||||||
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
dict[1218005070] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||||
dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) }
|
dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) }
|
||||||
dict[-1362048039] = { return Api.payments.ExportedInvoice.parse_exportedInvoice($0) }
|
dict[-1362048039] = { return Api.payments.ExportedInvoice.parse_exportedInvoice($0) }
|
||||||
dict[-1610250415] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
|
dict[-1610250415] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
|
||||||
@ -1522,6 +1522,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessagePeerReaction:
|
case let _1 as Api.MessagePeerReaction:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.MessagePeerVote:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessageRange:
|
case let _1 as Api.MessageRange:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessageReactions:
|
case let _1 as Api.MessageReactions:
|
||||||
@ -1530,8 +1532,6 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessageReplyHeader:
|
case let _1 as Api.MessageReplyHeader:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessageUserVote:
|
|
||||||
_1.serialize(buffer, boxed)
|
|
||||||
case let _1 as Api.MessageViews:
|
case let _1 as Api.MessageViews:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.MessagesFilter:
|
case let _1 as Api.MessagesFilter:
|
||||||
|
|||||||
@ -50,6 +50,114 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public extension Api {
|
||||||
|
enum MessagePeerVote: TypeConstructorDescription {
|
||||||
|
case messagePeerVote(peer: Api.Peer, option: Buffer, date: Int32)
|
||||||
|
case messagePeerVoteInputOption(peer: Api.Peer, date: Int32)
|
||||||
|
case messagePeerVoteMultiple(peer: Api.Peer, options: [Buffer], date: Int32)
|
||||||
|
|
||||||
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
|
switch self {
|
||||||
|
case .messagePeerVote(let peer, let option, let date):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(-1228133028)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeBytes(option, buffer: buffer, boxed: false)
|
||||||
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .messagePeerVoteInputOption(let peer, let date):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1959634180)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
case .messagePeerVoteMultiple(let peer, let options, let date):
|
||||||
|
if boxed {
|
||||||
|
buffer.appendInt32(1177089766)
|
||||||
|
}
|
||||||
|
peer.serialize(buffer, true)
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(options.count))
|
||||||
|
for item in options {
|
||||||
|
serializeBytes(item, buffer: buffer, boxed: false)
|
||||||
|
}
|
||||||
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
|
switch self {
|
||||||
|
case .messagePeerVote(let peer, let option, let date):
|
||||||
|
return ("messagePeerVote", [("peer", peer as Any), ("option", option as Any), ("date", date as Any)])
|
||||||
|
case .messagePeerVoteInputOption(let peer, let date):
|
||||||
|
return ("messagePeerVoteInputOption", [("peer", peer as Any), ("date", date as Any)])
|
||||||
|
case .messagePeerVoteMultiple(let peer, let options, let date):
|
||||||
|
return ("messagePeerVoteMultiple", [("peer", peer as Any), ("options", options as Any), ("date", date as Any)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func parse_messagePeerVote(_ reader: BufferReader) -> MessagePeerVote? {
|
||||||
|
var _1: Api.Peer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||||
|
}
|
||||||
|
var _2: Buffer?
|
||||||
|
_2 = parseBytes(reader)
|
||||||
|
var _3: Int32?
|
||||||
|
_3 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.MessagePeerVote.messagePeerVote(peer: _1!, option: _2!, date: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_messagePeerVoteInputOption(_ reader: BufferReader) -> MessagePeerVote? {
|
||||||
|
var _1: Api.Peer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||||
|
}
|
||||||
|
var _2: Int32?
|
||||||
|
_2 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
if _c1 && _c2 {
|
||||||
|
return Api.MessagePeerVote.messagePeerVoteInputOption(peer: _1!, date: _2!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static func parse_messagePeerVoteMultiple(_ reader: BufferReader) -> MessagePeerVote? {
|
||||||
|
var _1: Api.Peer?
|
||||||
|
if let signature = reader.readInt32() {
|
||||||
|
_1 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||||
|
}
|
||||||
|
var _2: [Buffer]?
|
||||||
|
if let _ = reader.readInt32() {
|
||||||
|
_2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
|
||||||
|
}
|
||||||
|
var _3: Int32?
|
||||||
|
_3 = reader.readInt32()
|
||||||
|
let _c1 = _1 != nil
|
||||||
|
let _c2 = _2 != nil
|
||||||
|
let _c3 = _3 != nil
|
||||||
|
if _c1 && _c2 && _c3 {
|
||||||
|
return Api.MessagePeerVote.messagePeerVoteMultiple(peer: _1!, options: _2!, date: _3!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum MessageRange: TypeConstructorDescription {
|
enum MessageRange: TypeConstructorDescription {
|
||||||
case messageRange(minId: Int32, maxId: Int32)
|
case messageRange(minId: Int32, maxId: Int32)
|
||||||
@ -262,108 +370,6 @@ public extension Api {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api {
|
|
||||||
enum MessageUserVote: TypeConstructorDescription {
|
|
||||||
case messageUserVote(userId: Int64, option: Buffer, date: Int32)
|
|
||||||
case messageUserVoteInputOption(userId: Int64, date: Int32)
|
|
||||||
case messageUserVoteMultiple(userId: Int64, options: [Buffer], date: Int32)
|
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
|
||||||
switch self {
|
|
||||||
case .messageUserVote(let userId, let option, let date):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(886196148)
|
|
||||||
}
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
serializeBytes(option, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(date, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .messageUserVoteInputOption(let userId, let date):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(1017491692)
|
|
||||||
}
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
serializeInt32(date, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
case .messageUserVoteMultiple(let userId, let options, let date):
|
|
||||||
if boxed {
|
|
||||||
buffer.appendInt32(-1973033641)
|
|
||||||
}
|
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(options.count))
|
|
||||||
for item in options {
|
|
||||||
serializeBytes(item, buffer: buffer, boxed: false)
|
|
||||||
}
|
|
||||||
serializeInt32(date, buffer: buffer, boxed: false)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
|
||||||
switch self {
|
|
||||||
case .messageUserVote(let userId, let option, let date):
|
|
||||||
return ("messageUserVote", [("userId", userId as Any), ("option", option as Any), ("date", date as Any)])
|
|
||||||
case .messageUserVoteInputOption(let userId, let date):
|
|
||||||
return ("messageUserVoteInputOption", [("userId", userId as Any), ("date", date as Any)])
|
|
||||||
case .messageUserVoteMultiple(let userId, let options, let date):
|
|
||||||
return ("messageUserVoteMultiple", [("userId", userId as Any), ("options", options as Any), ("date", date as Any)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func parse_messageUserVote(_ reader: BufferReader) -> MessageUserVote? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Buffer?
|
|
||||||
_2 = parseBytes(reader)
|
|
||||||
var _3: Int32?
|
|
||||||
_3 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.MessageUserVote.messageUserVote(userId: _1!, option: _2!, date: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_messageUserVoteInputOption(_ reader: BufferReader) -> MessageUserVote? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: Int32?
|
|
||||||
_2 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
if _c1 && _c2 {
|
|
||||||
return Api.MessageUserVote.messageUserVoteInputOption(userId: _1!, date: _2!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static func parse_messageUserVoteMultiple(_ reader: BufferReader) -> MessageUserVote? {
|
|
||||||
var _1: Int64?
|
|
||||||
_1 = reader.readInt64()
|
|
||||||
var _2: [Buffer]?
|
|
||||||
if let _ = reader.readInt32() {
|
|
||||||
_2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
|
|
||||||
}
|
|
||||||
var _3: Int32?
|
|
||||||
_3 = reader.readInt32()
|
|
||||||
let _c1 = _1 != nil
|
|
||||||
let _c2 = _2 != nil
|
|
||||||
let _c3 = _3 != nil
|
|
||||||
if _c1 && _c2 && _c3 {
|
|
||||||
return Api.MessageUserVote.messageUserVoteMultiple(userId: _1!, options: _2!, date: _3!)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum MessageViews: TypeConstructorDescription {
|
enum MessageViews: TypeConstructorDescription {
|
||||||
case messageViews(flags: Int32, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?)
|
case messageViews(flags: Int32, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?)
|
||||||
|
|||||||
@ -428,13 +428,13 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum PollResults: TypeConstructorDescription {
|
enum PollResults: TypeConstructorDescription {
|
||||||
case pollResults(flags: Int32, results: [Api.PollAnswerVoters]?, totalVoters: Int32?, recentVoters: [Int64]?, solution: String?, solutionEntities: [Api.MessageEntity]?)
|
case pollResults(flags: Int32, results: [Api.PollAnswerVoters]?, totalVoters: Int32?, recentVoters: [Api.Peer]?, solution: String?, solutionEntities: [Api.MessageEntity]?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .pollResults(let flags, let results, let totalVoters, let recentVoters, let solution, let solutionEntities):
|
case .pollResults(let flags, let results, let totalVoters, let recentVoters, let solution, let solutionEntities):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-591909213)
|
buffer.appendInt32(2061444128)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
|
||||||
@ -446,7 +446,7 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(recentVoters!.count))
|
buffer.appendInt32(Int32(recentVoters!.count))
|
||||||
for item in recentVoters! {
|
for item in recentVoters! {
|
||||||
serializeInt64(item, buffer: buffer, boxed: false)
|
item.serialize(buffer, true)
|
||||||
}}
|
}}
|
||||||
if Int(flags) & Int(1 << 4) != 0 {serializeString(solution!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 4) != 0 {serializeString(solution!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261)
|
||||||
@ -474,9 +474,9 @@ public extension Api {
|
|||||||
} }
|
} }
|
||||||
var _3: Int32?
|
var _3: Int32?
|
||||||
if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() }
|
if Int(_1!) & Int(1 << 2) != 0 {_3 = reader.readInt32() }
|
||||||
var _4: [Int64]?
|
var _4: [Api.Peer]?
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
||||||
_4 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
|
||||||
} }
|
} }
|
||||||
var _5: String?
|
var _5: String?
|
||||||
if Int(_1!) & Int(1 << 4) != 0 {_5 = parseString(reader) }
|
if Int(_1!) & Int(1 << 4) != 0 {_5 = parseString(reader) }
|
||||||
|
|||||||
@ -785,7 +785,7 @@ public extension Api {
|
|||||||
case updateMessageExtendedMedia(peer: Api.Peer, msgId: Int32, extendedMedia: Api.MessageExtendedMedia)
|
case updateMessageExtendedMedia(peer: Api.Peer, msgId: Int32, extendedMedia: Api.MessageExtendedMedia)
|
||||||
case updateMessageID(id: Int32, randomId: Int64)
|
case updateMessageID(id: Int32, randomId: Int64)
|
||||||
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
|
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
|
||||||
case updateMessagePollVote(pollId: Int64, userId: Int64, options: [Buffer], qts: Int32)
|
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32)
|
||||||
case updateMessageReactions(flags: Int32, peer: Api.Peer, msgId: Int32, topMsgId: Int32?, reactions: Api.MessageReactions)
|
case updateMessageReactions(flags: Int32, peer: Api.Peer, msgId: Int32, topMsgId: Int32?, reactions: Api.MessageReactions)
|
||||||
case updateMoveStickerSetToTop(flags: Int32, stickerset: Int64)
|
case updateMoveStickerSetToTop(flags: Int32, stickerset: Int64)
|
||||||
case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32)
|
case updateNewChannelMessage(message: Api.Message, pts: Int32, ptsCount: Int32)
|
||||||
@ -1385,12 +1385,12 @@ public extension Api {
|
|||||||
if Int(flags) & Int(1 << 0) != 0 {poll!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 0) != 0 {poll!.serialize(buffer, true)}
|
||||||
results.serialize(buffer, true)
|
results.serialize(buffer, true)
|
||||||
break
|
break
|
||||||
case .updateMessagePollVote(let pollId, let userId, let options, let qts):
|
case .updateMessagePollVote(let pollId, let peer, let options, let qts):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(274961865)
|
buffer.appendInt32(619974263)
|
||||||
}
|
}
|
||||||
serializeInt64(pollId, buffer: buffer, boxed: false)
|
serializeInt64(pollId, buffer: buffer, boxed: false)
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
peer.serialize(buffer, true)
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(options.count))
|
buffer.appendInt32(Int32(options.count))
|
||||||
for item in options {
|
for item in options {
|
||||||
@ -1923,8 +1923,8 @@ public extension Api {
|
|||||||
return ("updateMessageID", [("id", id as Any), ("randomId", randomId as Any)])
|
return ("updateMessageID", [("id", id as Any), ("randomId", randomId as Any)])
|
||||||
case .updateMessagePoll(let flags, let pollId, let poll, let results):
|
case .updateMessagePoll(let flags, let pollId, let poll, let results):
|
||||||
return ("updateMessagePoll", [("flags", flags as Any), ("pollId", pollId as Any), ("poll", poll as Any), ("results", results as Any)])
|
return ("updateMessagePoll", [("flags", flags as Any), ("pollId", pollId as Any), ("poll", poll as Any), ("results", results as Any)])
|
||||||
case .updateMessagePollVote(let pollId, let userId, let options, let qts):
|
case .updateMessagePollVote(let pollId, let peer, let options, let qts):
|
||||||
return ("updateMessagePollVote", [("pollId", pollId as Any), ("userId", userId as Any), ("options", options as Any), ("qts", qts as Any)])
|
return ("updateMessagePollVote", [("pollId", pollId as Any), ("peer", peer as Any), ("options", options as Any), ("qts", qts as Any)])
|
||||||
case .updateMessageReactions(let flags, let peer, let msgId, let topMsgId, let reactions):
|
case .updateMessageReactions(let flags, let peer, let msgId, let topMsgId, let reactions):
|
||||||
return ("updateMessageReactions", [("flags", flags as Any), ("peer", peer as Any), ("msgId", msgId as Any), ("topMsgId", topMsgId as Any), ("reactions", reactions as Any)])
|
return ("updateMessageReactions", [("flags", flags as Any), ("peer", peer as Any), ("msgId", msgId as Any), ("topMsgId", topMsgId as Any), ("reactions", reactions as Any)])
|
||||||
case .updateMoveStickerSetToTop(let flags, let stickerset):
|
case .updateMoveStickerSetToTop(let flags, let stickerset):
|
||||||
@ -3171,8 +3171,10 @@ public extension Api {
|
|||||||
public static func parse_updateMessagePollVote(_ reader: BufferReader) -> Update? {
|
public static func parse_updateMessagePollVote(_ reader: BufferReader) -> Update? {
|
||||||
var _1: Int64?
|
var _1: Int64?
|
||||||
_1 = reader.readInt64()
|
_1 = reader.readInt64()
|
||||||
var _2: Int64?
|
var _2: Api.Peer?
|
||||||
_2 = reader.readInt64()
|
if let signature = reader.readInt32() {
|
||||||
|
_2 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||||
|
}
|
||||||
var _3: [Buffer]?
|
var _3: [Buffer]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
|
_3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
|
||||||
@ -3184,7 +3186,7 @@ public extension Api {
|
|||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
if _c1 && _c2 && _c3 && _c4 {
|
||||||
return Api.Update.updateMessagePollVote(pollId: _1!, userId: _2!, options: _3!, qts: _4!)
|
return Api.Update.updateMessagePollVote(pollId: _1!, peer: _2!, options: _3!, qts: _4!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -198,13 +198,13 @@ public extension Api.messages {
|
|||||||
}
|
}
|
||||||
public extension Api.messages {
|
public extension Api.messages {
|
||||||
enum VotesList: TypeConstructorDescription {
|
enum VotesList: TypeConstructorDescription {
|
||||||
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
|
case votesList(flags: Int32, count: Int32, votes: [Api.MessagePeerVote], chats: [Api.Chat], users: [Api.User], nextOffset: String?)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
case .votesList(let flags, let count, let votes, let chats, let users, let nextOffset):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(136574537)
|
buffer.appendInt32(1218005070)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(count, buffer: buffer, boxed: false)
|
serializeInt32(count, buffer: buffer, boxed: false)
|
||||||
@ -214,6 +214,11 @@ public extension Api.messages {
|
|||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}
|
}
|
||||||
buffer.appendInt32(481674261)
|
buffer.appendInt32(481674261)
|
||||||
|
buffer.appendInt32(Int32(chats.count))
|
||||||
|
for item in chats {
|
||||||
|
item.serialize(buffer, true)
|
||||||
|
}
|
||||||
|
buffer.appendInt32(481674261)
|
||||||
buffer.appendInt32(Int32(users.count))
|
buffer.appendInt32(Int32(users.count))
|
||||||
for item in users {
|
for item in users {
|
||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
@ -225,8 +230,8 @@ public extension Api.messages {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
switch self {
|
||||||
case .votesList(let flags, let count, let votes, let users, let nextOffset):
|
case .votesList(let flags, let count, let votes, let chats, let users, let nextOffset):
|
||||||
return ("votesList", [("flags", flags as Any), ("count", count as Any), ("votes", votes as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
|
return ("votesList", [("flags", flags as Any), ("count", count as Any), ("votes", votes as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,23 +240,28 @@ public extension Api.messages {
|
|||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
var _2: Int32?
|
var _2: Int32?
|
||||||
_2 = reader.readInt32()
|
_2 = reader.readInt32()
|
||||||
var _3: [Api.MessageUserVote]?
|
var _3: [Api.MessagePeerVote]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessagePeerVote.self)
|
||||||
}
|
}
|
||||||
var _4: [Api.User]?
|
var _4: [Api.Chat]?
|
||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||||
}
|
}
|
||||||
var _5: String?
|
var _5: [Api.User]?
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
if let _ = reader.readInt32() {
|
||||||
|
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||||
|
}
|
||||||
|
var _6: String?
|
||||||
|
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = _4 != nil
|
let _c4 = _4 != nil
|
||||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
let _c5 = _5 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||||
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
|
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||||
|
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, chats: _4!, users: _5!, nextOffset: _6)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -4546,25 +4546,6 @@ public extension Api.functions.messages {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public extension Api.functions.messages {
|
|
||||||
static func getAllChats(exceptIds: [Int64]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Chats>) {
|
|
||||||
let buffer = Buffer()
|
|
||||||
buffer.appendInt32(-2023787330)
|
|
||||||
buffer.appendInt32(481674261)
|
|
||||||
buffer.appendInt32(Int32(exceptIds.count))
|
|
||||||
for item in exceptIds {
|
|
||||||
serializeInt64(item, buffer: buffer, boxed: false)
|
|
||||||
}
|
|
||||||
return (FunctionDescription(name: "messages.getAllChats", parameters: [("exceptIds", String(describing: exceptIds))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Chats? in
|
|
||||||
let reader = BufferReader(buffer)
|
|
||||||
var result: Api.messages.Chats?
|
|
||||||
if let signature = reader.readInt32() {
|
|
||||||
result = Api.parse(reader, signature: signature) as? Api.messages.Chats
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public extension Api.functions.messages {
|
public extension Api.functions.messages {
|
||||||
static func getAllDrafts() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
static func getAllDrafts() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||||
let buffer = Buffer()
|
let buffer = Buffer()
|
||||||
|
|||||||
@ -114,10 +114,14 @@ private func mergeReactions(reactions: [MessageReaction], recentPeers: [Reaction
|
|||||||
pendingIndex += 1
|
pendingIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if let index = recentPeers.firstIndex(where: { $0.value == pendingReaction.value && $0.peerId == accountPeerId }) {
|
let pendingReactionSendAsPeerId = pendingReaction.sendAsPeerId ?? accountPeerId
|
||||||
|
|
||||||
|
if let index = recentPeers.firstIndex(where: {
|
||||||
|
$0.value == pendingReaction.value && $0.peerId == pendingReactionSendAsPeerId
|
||||||
|
}) {
|
||||||
recentPeers.remove(at: index)
|
recentPeers.remove(at: index)
|
||||||
}
|
}
|
||||||
recentPeers.append(ReactionsMessageAttribute.RecentPeer(value: pendingReaction.value, isLarge: false, isUnseen: false, peerId: accountPeerId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)))
|
recentPeers.append(ReactionsMessageAttribute.RecentPeer(value: pendingReaction.value, isLarge: false, isUnseen: false, peerId: pendingReactionSendAsPeerId, timestamp: Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in (0 ..< result.count).reversed() {
|
for i in (0 ..< result.count).reversed() {
|
||||||
|
|||||||
@ -35,7 +35,7 @@ extension TelegramMediaPollResults {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.init(voters: results.flatMap({ $0.map(TelegramMediaPollOptionVoters.init(apiVoters:)) }), totalVoters: totalVoters, recentVoters: recentVoters.flatMap { recentVoters in
|
self.init(voters: results.flatMap({ $0.map(TelegramMediaPollOptionVoters.init(apiVoters:)) }), totalVoters: totalVoters, recentVoters: recentVoters.flatMap { recentVoters in
|
||||||
return recentVoters.map { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }
|
return recentVoters.map { $0.peerId }
|
||||||
} ?? [], solution: parsedSolution)
|
} ?? [], solution: parsedSolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,15 @@ public enum UpdateMessageReaction {
|
|||||||
|
|
||||||
public func updateMessageReactionsInteractively(account: Account, messageId: MessageId, reactions: [UpdateMessageReaction], isLarge: Bool, storeAsRecentlyUsed: Bool) -> Signal<Never, NoError> {
|
public func updateMessageReactionsInteractively(account: Account, messageId: MessageId, reactions: [UpdateMessageReaction], isLarge: Bool, storeAsRecentlyUsed: Bool) -> Signal<Never, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Void in
|
return account.postbox.transaction { transaction -> Void in
|
||||||
|
var sendAsPeerId = account.peerId
|
||||||
|
if let cachedData = transaction.getPeerCachedData(peerId: messageId.peerId) {
|
||||||
|
if let cachedData = cachedData as? CachedChannelData {
|
||||||
|
if let sendAsPeerIdValue = cachedData.sendAsPeerId {
|
||||||
|
sendAsPeerId = sendAsPeerIdValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let isPremium = (transaction.getPeer(account.peerId) as? TelegramUser)?.isPremium ?? false
|
let isPremium = (transaction.getPeer(account.peerId) as? TelegramUser)?.isPremium ?? false
|
||||||
let appConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue
|
let appConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue
|
||||||
let maxCount: Int
|
let maxCount: Int
|
||||||
@ -34,12 +43,12 @@ public func updateMessageReactionsInteractively(account: Account, messageId: Mes
|
|||||||
for reaction in reactions {
|
for reaction in reactions {
|
||||||
switch reaction {
|
switch reaction {
|
||||||
case let .custom(fileId, file):
|
case let .custom(fileId, file):
|
||||||
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .custom(fileId)))
|
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .custom(fileId), sendAsPeerId: sendAsPeerId))
|
||||||
if let file = file {
|
if let file = file {
|
||||||
transaction.storeMediaIfNotPresent(media: file)
|
transaction.storeMediaIfNotPresent(media: file)
|
||||||
}
|
}
|
||||||
case let .builtin(value):
|
case let .builtin(value):
|
||||||
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .builtin(value)))
|
mappedReactions.append(PendingReactionsMessageAttribute.PendingReaction(value: .builtin(value), sendAsPeerId: sendAsPeerId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +97,7 @@ public func updateMessageReactionsInteractively(account: Account, messageId: Mes
|
|||||||
if updatedOutgoingReactions.count > maxCount {
|
if updatedOutgoingReactions.count > maxCount {
|
||||||
let sortedOutgoingReactions = updatedOutgoingReactions.sorted(by: { $0.chosenOrder! < $1.chosenOrder! })
|
let sortedOutgoingReactions = updatedOutgoingReactions.sorted(by: { $0.chosenOrder! < $1.chosenOrder! })
|
||||||
mappedReactions = Array(sortedOutgoingReactions.suffix(maxCount).map { reaction -> PendingReactionsMessageAttribute.PendingReaction in
|
mappedReactions = Array(sortedOutgoingReactions.suffix(maxCount).map { reaction -> PendingReactionsMessageAttribute.PendingReaction in
|
||||||
return PendingReactionsMessageAttribute.PendingReaction(value: reaction.value)
|
return PendingReactionsMessageAttribute.PendingReaction(value: reaction.value, sendAsPeerId: sendAsPeerId)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -446,20 +446,77 @@ public final class PendingMessageManager {
|
|||||||
|
|
||||||
Logger.shared.log("PendingMessageManager", "beginSendingMessages messagesToForward.count: \(messagesToForward.count)")
|
Logger.shared.log("PendingMessageManager", "beginSendingMessages messagesToForward.count: \(messagesToForward.count)")
|
||||||
|
|
||||||
|
let forwardGroupLimit = 100
|
||||||
for (_, messages) in messagesToForward {
|
for (_, ungroupedMessages) in messagesToForward {
|
||||||
for (context, _, _) in messages {
|
var messageGroups: [[(PendingMessageContext, Message, ForwardSourceInfoAttribute)]] = []
|
||||||
context.state = .sending(groupId: nil)
|
|
||||||
|
for message in ungroupedMessages {
|
||||||
|
if messageGroups.isEmpty || messageGroups[messageGroups.count - 1].isEmpty {
|
||||||
|
messageGroups.append([message])
|
||||||
|
} else {
|
||||||
|
if messageGroups[messageGroups.count - 1][0].1.groupingKey == message.1.groupingKey {
|
||||||
|
messageGroups[messageGroups.count - 1].append(message)
|
||||||
|
} else {
|
||||||
|
messageGroups.append([message])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let sendMessage: Signal<PendingMessageResult, NoError> = strongSelf.sendGroupMessagesContent(network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, accountPeerId: strongSelf.accountPeerId, group: messages.map { data in
|
|
||||||
let (_, message, forwardInfo) = data
|
var countedMessageGroups: [[(PendingMessageContext, Message, ForwardSourceInfoAttribute)]] = []
|
||||||
return (message.id, PendingMessageUploadedContentAndReuploadInfo(content: .forward(forwardInfo), reuploadInfo: nil, cacheReferenceKey: nil))
|
while !messageGroups.isEmpty {
|
||||||
})
|
guard let messageGroup = messageGroups.first else {
|
||||||
|> map { next -> PendingMessageResult in
|
break
|
||||||
return .progress(1.0)
|
}
|
||||||
|
|
||||||
|
messageGroups.removeFirst()
|
||||||
|
|
||||||
|
if messageGroup.isEmpty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if countedMessageGroups.isEmpty {
|
||||||
|
countedMessageGroups.append([])
|
||||||
|
} else if countedMessageGroups[countedMessageGroups.count - 1].count >= forwardGroupLimit {
|
||||||
|
countedMessageGroups.append([])
|
||||||
|
}
|
||||||
|
|
||||||
|
if countedMessageGroups[countedMessageGroups.count - 1].isEmpty {
|
||||||
|
let fittingFreeMessageCount = min(forwardGroupLimit, messageGroup.count)
|
||||||
|
countedMessageGroups[countedMessageGroups.count - 1].append(contentsOf: messageGroup[0 ..< fittingFreeMessageCount])
|
||||||
|
if fittingFreeMessageCount < messageGroup.count {
|
||||||
|
messageGroups.insert(Array(messageGroup[fittingFreeMessageCount ..< messageGroup.count]), at: 0)
|
||||||
|
}
|
||||||
|
} else if countedMessageGroups[countedMessageGroups.count - 1].count + messageGroup.count <= forwardGroupLimit {
|
||||||
|
countedMessageGroups[countedMessageGroups.count - 1].append(contentsOf: messageGroup)
|
||||||
|
} else {
|
||||||
|
if countedMessageGroups[countedMessageGroups.count - 1][0].1.groupingKey == nil && messageGroup[0].1.groupingKey == nil {
|
||||||
|
let fittingFreeMessageCount = forwardGroupLimit - countedMessageGroups[countedMessageGroups.count - 1].count
|
||||||
|
countedMessageGroups[countedMessageGroups.count - 1].append(contentsOf: messageGroup[0 ..< fittingFreeMessageCount])
|
||||||
|
messageGroups.insert(Array(messageGroup[fittingFreeMessageCount ..< messageGroup.count]), at: 0)
|
||||||
|
} else {
|
||||||
|
countedMessageGroups.append([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for messages in countedMessageGroups {
|
||||||
|
if messages.isEmpty {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (context, _, _) in messages {
|
||||||
|
context.state = .sending(groupId: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
let sendMessage: Signal<PendingMessageResult, NoError> = strongSelf.sendGroupMessagesContent(network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, accountPeerId: strongSelf.accountPeerId, group: messages.map { data in
|
||||||
|
let (_, message, forwardInfo) = data
|
||||||
|
return (message.id, PendingMessageUploadedContentAndReuploadInfo(content: .forward(forwardInfo), reuploadInfo: nil, cacheReferenceKey: nil))
|
||||||
|
})
|
||||||
|
|> map { next -> PendingMessageResult in
|
||||||
|
return .progress(1.0)
|
||||||
|
}
|
||||||
|
messages[0].0.sendDisposable.set((sendMessage
|
||||||
|
|> deliverOn(strongSelf.queue)).start())
|
||||||
}
|
}
|
||||||
messages[0].0.sendDisposable.set((sendMessage
|
|
||||||
|> deliverOn(strongSelf.queue)).start())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|||||||
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 158
|
return 159
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
|||||||
@ -241,17 +241,25 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute {
|
|||||||
public final class PendingReactionsMessageAttribute: MessageAttribute {
|
public final class PendingReactionsMessageAttribute: MessageAttribute {
|
||||||
public struct PendingReaction: Equatable, PostboxCoding {
|
public struct PendingReaction: Equatable, PostboxCoding {
|
||||||
public var value: MessageReaction.Reaction
|
public var value: MessageReaction.Reaction
|
||||||
|
public var sendAsPeerId: PeerId?
|
||||||
|
|
||||||
public init(value: MessageReaction.Reaction) {
|
public init(value: MessageReaction.Reaction, sendAsPeerId: PeerId?) {
|
||||||
self.value = value
|
self.value = value
|
||||||
|
self.sendAsPeerId = sendAsPeerId
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.value = decoder.decodeObjectForKey("val", decoder: { MessageReaction.Reaction(decoder: $0) }) as! MessageReaction.Reaction
|
self.value = decoder.decodeObjectForKey("val", decoder: { MessageReaction.Reaction(decoder: $0) }) as! MessageReaction.Reaction
|
||||||
|
self.sendAsPeerId = decoder.decodeOptionalInt64ForKey("sa").flatMap(PeerId.init)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeObject(self.value, forKey: "val")
|
encoder.encodeObject(self.value, forKey: "val")
|
||||||
|
if let sendAsPeerId = self.sendAsPeerId {
|
||||||
|
encoder.encodeInt64(sendAsPeerId.toInt64(), forKey: "sa")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "sa")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,11 +269,18 @@ public final class PendingReactionsMessageAttribute: MessageAttribute {
|
|||||||
public let storeAsRecentlyUsed: Bool
|
public let storeAsRecentlyUsed: Bool
|
||||||
|
|
||||||
public var associatedPeerIds: [PeerId] {
|
public var associatedPeerIds: [PeerId] {
|
||||||
|
var peerIds: [PeerId] = []
|
||||||
if let accountPeerId = self.accountPeerId {
|
if let accountPeerId = self.accountPeerId {
|
||||||
return [accountPeerId]
|
peerIds.append(accountPeerId)
|
||||||
} else {
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
for reaction in self.reactions {
|
||||||
|
if let sendAsPeerId = reaction.sendAsPeerId {
|
||||||
|
if !peerIds.contains(sendAsPeerId) {
|
||||||
|
peerIds.append(sendAsPeerId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peerIds
|
||||||
}
|
}
|
||||||
|
|
||||||
public var associatedMediaIds: [MediaId] {
|
public var associatedMediaIds: [MediaId] {
|
||||||
|
|||||||
@ -272,8 +272,13 @@ private final class PollResultsOptionContext {
|
|||||||
return ([], 0, nil)
|
return ([], 0, nil)
|
||||||
}
|
}
|
||||||
switch result {
|
switch result {
|
||||||
case let .votesList(_, count, votes, users, nextOffset):
|
case let .votesList(_, count, votes, chats, users, nextOffset):
|
||||||
var peers: [Peer] = []
|
var peers: [Peer] = []
|
||||||
|
for apiChat in chats {
|
||||||
|
if let peer = parseTelegramGroupOrChannel(chat: apiChat) {
|
||||||
|
peers.append(peer)
|
||||||
|
}
|
||||||
|
}
|
||||||
for apiUser in users {
|
for apiUser in users {
|
||||||
peers.append(TelegramUser(user: apiUser))
|
peers.append(TelegramUser(user: apiUser))
|
||||||
}
|
}
|
||||||
@ -284,12 +289,12 @@ private final class PollResultsOptionContext {
|
|||||||
for vote in votes {
|
for vote in votes {
|
||||||
let peerId: PeerId
|
let peerId: PeerId
|
||||||
switch vote {
|
switch vote {
|
||||||
case let .messageUserVote(userId, _, _):
|
case let .messagePeerVote(peerIdValue, _, _):
|
||||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
peerId = peerIdValue.peerId
|
||||||
case let .messageUserVoteInputOption(userId, _):
|
case let .messagePeerVoteInputOption(peerIdValue, _):
|
||||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
peerId = peerIdValue.peerId
|
||||||
case let .messageUserVoteMultiple(userId, _, _):
|
case let .messagePeerVoteMultiple(peerIdValue, _, _):
|
||||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
peerId = peerIdValue.peerId
|
||||||
}
|
}
|
||||||
if let peer = transaction.getPeer(peerId) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
resultPeers.append(RenderedPeer(peer: peer))
|
resultPeers.append(RenderedPeer(peer: peer))
|
||||||
|
|||||||
@ -360,6 +360,9 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/SliderContextItem:SliderContextItem",
|
"//submodules/TelegramUI/Components/SliderContextItem:SliderContextItem",
|
||||||
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
|
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
|
||||||
"//submodules/TelegramUI/Components/Stories/StoryContentComponent",
|
"//submodules/TelegramUI/Components/Stories/StoryContentComponent",
|
||||||
|
"//submodules/TelegramUI/Components/ChatScheduleTimeController",
|
||||||
|
"//submodules/ICloudResources",
|
||||||
|
"//submodules/TelegramUI/Components/LegacyCamera",
|
||||||
] + select({
|
] + select({
|
||||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "ChatScheduleTimeController",
|
||||||
|
module_name = "ChatScheduleTimeController",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
|
"//submodules/AsyncDisplayKit",
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/Postbox",
|
||||||
|
"//submodules/AccountContext",
|
||||||
|
"//submodules/TelegramPresentationData",
|
||||||
|
"//submodules/TelegramStringFormatting",
|
||||||
|
"//submodules/SolidRoundedButtonNode",
|
||||||
|
"//submodules/PresentationDataUtils",
|
||||||
|
"//submodules/UIKitRuntimeUtils",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -8,17 +8,17 @@ import SwiftSignalKit
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
enum ChatScheduleTimeControllerMode {
|
public enum ChatScheduleTimeControllerMode {
|
||||||
case scheduledMessages(sendWhenOnlineAvailable: Bool)
|
case scheduledMessages(sendWhenOnlineAvailable: Bool)
|
||||||
case reminders
|
case reminders
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ChatScheduleTimeControllerStyle {
|
public enum ChatScheduleTimeControllerStyle {
|
||||||
case `default`
|
case `default`
|
||||||
case media
|
case media
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ChatScheduleTimeController: ViewController {
|
public final class ChatScheduleTimeController: ViewController {
|
||||||
private var controllerNode: ChatScheduleTimeControllerNode {
|
private var controllerNode: ChatScheduleTimeControllerNode {
|
||||||
return self.displayNode as! ChatScheduleTimeControllerNode
|
return self.displayNode as! ChatScheduleTimeControllerNode
|
||||||
}
|
}
|
||||||
@ -37,7 +37,7 @@ final class ChatScheduleTimeController: ViewController {
|
|||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
|
|
||||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, mode: ChatScheduleTimeControllerMode, style: ChatScheduleTimeControllerStyle, currentTime: Int32? = nil, minimalTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) {
|
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, mode: ChatScheduleTimeControllerMode, style: ChatScheduleTimeControllerStyle, currentTime: Int32? = nil, minimalTime: Int32? = nil, dismissByTapOutside: Bool = true, completion: @escaping (Int32) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
@ -66,7 +66,7 @@ final class ChatScheduleTimeController: ViewController {
|
|||||||
self.statusBar.statusBarStyle = .Ignore
|
self.statusBar.statusBarStyle = .Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
28
submodules/TelegramUI/Components/LegacyCamera/BUILD
Normal file
28
submodules/TelegramUI/Components/LegacyCamera/BUILD
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "LegacyCamera",
|
||||||
|
module_name = "LegacyCamera",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
|
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||||
|
"//submodules/LegacyComponents",
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/TelegramCore",
|
||||||
|
"//submodules/Postbox",
|
||||||
|
"//submodules/AccountContext",
|
||||||
|
"//submodules/ShareController",
|
||||||
|
"//submodules/LegacyUI",
|
||||||
|
"//submodules/LegacyMediaPickerUI",
|
||||||
|
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -10,7 +10,7 @@ import ShareController
|
|||||||
import LegacyUI
|
import LegacyUI
|
||||||
import LegacyMediaPickerUI
|
import LegacyMediaPickerUI
|
||||||
|
|
||||||
func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, enablePhoto: Bool, enableVideo: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
public func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: ChatLocation, cameraView: TGAttachmentCameraView?, menuController: TGMenuSheetController?, parentController: ViewController, attachmentController: ViewController? = nil, editingMedia: Bool, saveCapturedPhotos: Bool, mediaGrouping: Bool, initialCaption: NSAttributedString, hasSchedule: Bool, enablePhoto: Bool, enableVideo: Bool, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32) -> Void, recognizedQRCode: @escaping (String) -> Void = { _ in }, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, dismissedWithResult: @escaping () -> Void = {}, finishedTransitionIn: @escaping () -> Void = {}) {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||||
@ -202,7 +202,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, chatLocation: Ch
|
|||||||
parentController.present(legacyController, in: .window(.root))
|
parentController.present(legacyController, in: .window(.root))
|
||||||
}
|
}
|
||||||
|
|
||||||
func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedMedia: Bool, saveEditedPhotos: Bool, mediaGrouping: Bool, parentController: ViewController) {
|
public func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedMedia: Bool, saveEditedPhotos: Bool, mediaGrouping: Bool, parentController: ViewController) {
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme)
|
||||||
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
legacyController.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .portrait, compactSize: .portrait)
|
||||||
@ -14,6 +14,7 @@ swift_library(
|
|||||||
"//submodules/ComponentFlow",
|
"//submodules/ComponentFlow",
|
||||||
"//submodules/AppBundle",
|
"//submodules/AppBundle",
|
||||||
"//submodules/TelegramUI/Components/TextFieldComponent",
|
"//submodules/TelegramUI/Components/TextFieldComponent",
|
||||||
|
"//submodules/Components/BundleIconComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import Display
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import TextFieldComponent
|
import TextFieldComponent
|
||||||
|
import BundleIconComponent
|
||||||
|
|
||||||
public final class MessageInputPanelComponent: Component {
|
public final class MessageInputPanelComponent: Component {
|
||||||
public final class ExternalState {
|
public final class ExternalState {
|
||||||
@ -15,13 +16,16 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
|
|
||||||
public let externalState: ExternalState
|
public let externalState: ExternalState
|
||||||
public let sendMessageAction: () -> Void
|
public let sendMessageAction: () -> Void
|
||||||
|
public let attachmentAction: () -> Void
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
externalState: ExternalState,
|
externalState: ExternalState,
|
||||||
sendMessageAction: @escaping () -> Void
|
sendMessageAction: @escaping () -> Void,
|
||||||
|
attachmentAction: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.externalState = externalState
|
self.externalState = externalState
|
||||||
self.sendMessageAction = sendMessageAction
|
self.sendMessageAction = sendMessageAction
|
||||||
|
self.attachmentAction = attachmentAction
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: MessageInputPanelComponent, rhs: MessageInputPanelComponent) -> Bool {
|
public static func ==(lhs: MessageInputPanelComponent, rhs: MessageInputPanelComponent) -> Bool {
|
||||||
@ -41,7 +45,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
private let textField = ComponentView<Empty>()
|
private let textField = ComponentView<Empty>()
|
||||||
private let textFieldExternalState = TextFieldComponent.ExternalState()
|
private let textFieldExternalState = TextFieldComponent.ExternalState()
|
||||||
|
|
||||||
private let attachmentIconView: UIImageView
|
private let attachmentButton = ComponentView<Empty>()
|
||||||
private let inputActionButton = ComponentView<Empty>()
|
private let inputActionButton = ComponentView<Empty>()
|
||||||
private let stickerIconView: UIImageView
|
private let stickerIconView: UIImageView
|
||||||
|
|
||||||
@ -52,7 +56,6 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.fieldBackgroundView = UIImageView()
|
self.fieldBackgroundView = UIImageView()
|
||||||
self.attachmentIconView = UIImageView()
|
|
||||||
self.stickerIconView = UIImageView()
|
self.stickerIconView = UIImageView()
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -60,7 +63,6 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
self.addSubview(self.fieldBackgroundView)
|
self.addSubview(self.fieldBackgroundView)
|
||||||
|
|
||||||
self.addSubview(self.fieldBackgroundView)
|
self.addSubview(self.fieldBackgroundView)
|
||||||
self.addSubview(self.attachmentIconView)
|
|
||||||
self.addSubview(self.stickerIconView)
|
self.addSubview(self.stickerIconView)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +78,13 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
return .text(textFieldView.getText())
|
return .text(textFieldView.getText())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func getAttachmentButtonView() -> UIView? {
|
||||||
|
guard let attachmentButtonView = self.attachmentButton.view else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return attachmentButtonView
|
||||||
|
}
|
||||||
|
|
||||||
public func clearSendMessageInput() {
|
public func clearSendMessageInput() {
|
||||||
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
if let textFieldView = self.textField.view as? TextFieldComponent.View {
|
||||||
textFieldView.setText(string: "")
|
textFieldView.setText(string: "")
|
||||||
@ -93,10 +102,6 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
if self.fieldBackgroundView.image == nil {
|
if self.fieldBackgroundView.image == nil {
|
||||||
self.fieldBackgroundView.image = generateStretchableFilledCircleImage(diameter: fieldCornerRadius * 2.0, color: nil, strokeColor: UIColor(white: 1.0, alpha: 0.16), strokeWidth: 1.0, backgroundColor: nil)
|
self.fieldBackgroundView.image = generateStretchableFilledCircleImage(diameter: fieldCornerRadius * 2.0, color: nil, strokeColor: UIColor(white: 1.0, alpha: 0.16), strokeWidth: 1.0, backgroundColor: nil)
|
||||||
}
|
}
|
||||||
if self.attachmentIconView.image == nil {
|
|
||||||
self.attachmentIconView.image = UIImage(bundleImageName: "Chat/Input/Text/IconAttachment")?.withRenderingMode(.alwaysTemplate)
|
|
||||||
self.attachmentIconView.tintColor = .white
|
|
||||||
}
|
|
||||||
if self.stickerIconView.image == nil {
|
if self.stickerIconView.image == nil {
|
||||||
self.stickerIconView.image = UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconStickers")?.withRenderingMode(.alwaysTemplate)
|
self.stickerIconView.image = UIImage(bundleImageName: "Chat/Input/Text/AccessoryIconStickers")?.withRenderingMode(.alwaysTemplate)
|
||||||
self.stickerIconView.tintColor = .white
|
self.stickerIconView.tintColor = .white
|
||||||
@ -129,8 +134,28 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
transition.setFrame(view: textFieldView, frame: CGRect(origin: CGPoint(x: fieldFrame.minX, y: fieldFrame.maxY - textFieldSize.height), size: textFieldSize))
|
transition.setFrame(view: textFieldView, frame: CGRect(origin: CGPoint(x: fieldFrame.minX, y: fieldFrame.maxY - textFieldSize.height), size: textFieldSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let image = self.attachmentIconView.image {
|
let attachmentButtonSize = self.attachmentButton.update(
|
||||||
transition.setFrame(view: self.attachmentIconView, frame: CGRect(origin: CGPoint(x: floor((insets.left - image.size.width) * 0.5), y: size.height - baseHeight + floor((baseHeight - image.size.height) * 0.5)), size: image.size))
|
transition: transition,
|
||||||
|
component: AnyComponent(Button(
|
||||||
|
content: AnyComponent(BundleIconComponent(
|
||||||
|
name: "Chat/Input/Text/IconAttachment",
|
||||||
|
tintColor: .white
|
||||||
|
)),
|
||||||
|
action: { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.component?.attachmentAction()
|
||||||
|
}
|
||||||
|
).minSize(CGSize(width: 41.0, height: baseHeight))),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: 41.0, height: baseHeight)
|
||||||
|
)
|
||||||
|
if let attachmentButtonView = self.attachmentButton.view {
|
||||||
|
if attachmentButtonView.superview == nil {
|
||||||
|
self.addSubview(attachmentButtonView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: attachmentButtonView, frame: CGRect(origin: CGPoint(x: floor((insets.left - attachmentButtonSize.width) * 0.5), y: size.height - baseHeight + floor((baseHeight - attachmentButtonSize.height) * 0.5)), size: attachmentButtonSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputActionButtonSize = self.inputActionButton.update(
|
let inputActionButtonSize = self.inputActionButton.update(
|
||||||
|
|||||||
@ -15,12 +15,32 @@ swift_library(
|
|||||||
"//submodules/Components/ViewControllerComponent",
|
"//submodules/Components/ViewControllerComponent",
|
||||||
"//submodules/Components/ComponentDisplayAdapters",
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||||
|
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
||||||
"//submodules/AccountContext",
|
"//submodules/AccountContext",
|
||||||
"//submodules/SSignalKit/SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit",
|
||||||
"//submodules/AppBundle",
|
"//submodules/AppBundle",
|
||||||
"//submodules/TelegramCore",
|
"//submodules/TelegramCore",
|
||||||
"//submodules/ShareController",
|
"//submodules/ShareController",
|
||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
|
"//submodules/AttachmentUI",
|
||||||
|
"//submodules/TelegramUIPreferences",
|
||||||
|
"//submodules/MediaPickerUI",
|
||||||
|
"//submodules/LegacyMediaPickerUI",
|
||||||
|
"//submodules/LocationUI",
|
||||||
|
"//submodules/WebUI",
|
||||||
|
"//submodules/TelegramUI/Components/ChatScheduleTimeController",
|
||||||
|
"//submodules/TelegramUI/Components/ChatTimerScreen",
|
||||||
|
"//submodules/TextFormat",
|
||||||
|
"//submodules/PhoneNumberFormat",
|
||||||
|
"//submodules/ComposePollUI",
|
||||||
|
"//submodules/TelegramIntents",
|
||||||
|
"//submodules/LegacyUI",
|
||||||
|
"//submodules/WebSearchUI",
|
||||||
|
"//submodules/PremiumUI",
|
||||||
|
"//submodules/ICloudResources",
|
||||||
|
"//submodules/LegacyComponents",
|
||||||
|
"//submodules/TelegramUI/Components/LegacyCamera",
|
||||||
|
"//submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -4,6 +4,21 @@ import Display
|
|||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
|
|
||||||
final class MediaNavigationStripComponent: Component {
|
final class MediaNavigationStripComponent: Component {
|
||||||
|
final class EnvironmentType: Equatable {
|
||||||
|
let currentProgress: Double
|
||||||
|
|
||||||
|
init(currentProgress: Double) {
|
||||||
|
self.currentProgress = currentProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: EnvironmentType, rhs: EnvironmentType) -> Bool {
|
||||||
|
if lhs.currentProgress != rhs.currentProgress {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let index: Int
|
let index: Int
|
||||||
let count: Int
|
let count: Int
|
||||||
|
|
||||||
@ -23,10 +38,17 @@ final class MediaNavigationStripComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class ItemLayer: SimpleLayer {
|
private final class ItemLayer: SimpleLayer {
|
||||||
|
let foregroundLayer: SimpleLayer
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
|
self.foregroundLayer = SimpleLayer()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.cornerRadius = 1.5
|
self.cornerRadius = 1.5
|
||||||
|
|
||||||
|
self.foregroundLayer.cornerRadius = 1.5
|
||||||
|
self.addSublayer(self.foregroundLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
@ -34,6 +56,8 @@ final class MediaNavigationStripComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override init(layer: Any) {
|
override init(layer: Any) {
|
||||||
|
self.foregroundLayer = SimpleLayer()
|
||||||
|
|
||||||
super.init(layer: layer)
|
super.init(layer: layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,10 +76,10 @@ final class MediaNavigationStripComponent: Component {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(component: MediaNavigationStripComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: MediaNavigationStripComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||||
let spacing: CGFloat = 3.0
|
let spacing: CGFloat = 3.0
|
||||||
let itemHeight: CGFloat = 2.0
|
let itemHeight: CGFloat = 2.0
|
||||||
let minItemWidth: CGFloat = 3.0
|
let minItemWidth: CGFloat = 10.0
|
||||||
|
|
||||||
var validIndices: [Int] = []
|
var validIndices: [Int] = []
|
||||||
if component.count != 0 {
|
if component.count != 0 {
|
||||||
@ -110,7 +134,19 @@ final class MediaNavigationStripComponent: Component {
|
|||||||
|
|
||||||
transition.setFrame(layer: itemLayer, frame: itemFrame)
|
transition.setFrame(layer: itemLayer, frame: itemFrame)
|
||||||
|
|
||||||
itemLayer.backgroundColor = UIColor(white: 1.0, alpha: i == component.index ? 1.0 : 0.5).cgColor
|
itemLayer.backgroundColor = UIColor(white: 1.0, alpha: 0.5).cgColor
|
||||||
|
itemLayer.foregroundLayer.backgroundColor = UIColor(white: 1.0, alpha: 1.0).cgColor
|
||||||
|
|
||||||
|
let itemProgress: CGFloat
|
||||||
|
if i < component.index {
|
||||||
|
itemProgress = 1.0
|
||||||
|
} else if i == component.index {
|
||||||
|
itemProgress = max(0.0, min(1.0, environment[EnvironmentType.self].value.currentProgress))
|
||||||
|
} else {
|
||||||
|
itemProgress = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.setFrame(layer: itemLayer.foregroundLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: itemProgress * itemFrame.width, height: itemFrame.height)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +169,7 @@ final class MediaNavigationStripComponent: Component {
|
|||||||
return View(frame: CGRect())
|
return View(frame: CGRect())
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -6,24 +6,51 @@ import SwiftSignalKit
|
|||||||
import TelegramCore
|
import TelegramCore
|
||||||
|
|
||||||
public final class StoryContentItem {
|
public final class StoryContentItem {
|
||||||
|
public final class ExternalState {
|
||||||
|
public init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Environment: Equatable {
|
||||||
|
public let externalState: ExternalState
|
||||||
|
public let presentationProgressUpdated: (Double) -> Void
|
||||||
|
|
||||||
|
public init(
|
||||||
|
externalState: ExternalState,
|
||||||
|
presentationProgressUpdated: @escaping (Double) -> Void
|
||||||
|
) {
|
||||||
|
self.externalState = externalState
|
||||||
|
self.presentationProgressUpdated = presentationProgressUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: Environment, rhs: Environment) -> Bool {
|
||||||
|
if lhs.externalState !== rhs.externalState {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public let id: AnyHashable
|
public let id: AnyHashable
|
||||||
public let position: Int
|
public let position: Int
|
||||||
public let component: AnyComponent<Empty>
|
public let component: AnyComponent<StoryContentItem.Environment>
|
||||||
public let centerInfoComponent: AnyComponent<Empty>?
|
public let centerInfoComponent: AnyComponent<Empty>?
|
||||||
public let rightInfoComponent: AnyComponent<Empty>?
|
public let rightInfoComponent: AnyComponent<Empty>?
|
||||||
public let targetMessageId: EngineMessage.Id?
|
public let targetMessageId: EngineMessage.Id?
|
||||||
public let preload: Signal<Never, NoError>?
|
public let preload: Signal<Never, NoError>?
|
||||||
public let hasLike: Bool
|
public let hasLike: Bool
|
||||||
|
public let isMy: Bool
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
id: AnyHashable,
|
id: AnyHashable,
|
||||||
position: Int,
|
position: Int,
|
||||||
component: AnyComponent<Empty>,
|
component: AnyComponent<StoryContentItem.Environment>,
|
||||||
centerInfoComponent: AnyComponent<Empty>?,
|
centerInfoComponent: AnyComponent<Empty>?,
|
||||||
rightInfoComponent: AnyComponent<Empty>?,
|
rightInfoComponent: AnyComponent<Empty>?,
|
||||||
targetMessageId: EngineMessage.Id?,
|
targetMessageId: EngineMessage.Id?,
|
||||||
preload: Signal<Never, NoError>?,
|
preload: Signal<Never, NoError>?,
|
||||||
hasLike: Bool
|
hasLike: Bool,
|
||||||
|
isMy: Bool
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.position = position
|
self.position = position
|
||||||
@ -33,6 +60,7 @@ public final class StoryContentItem {
|
|||||||
self.targetMessageId = targetMessageId
|
self.targetMessageId = targetMessageId
|
||||||
self.preload = preload
|
self.preload = preload
|
||||||
self.hasLike = hasLike
|
self.hasLike = hasLike
|
||||||
|
self.isMy = isMy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,8 @@ public enum StoryChatContent {
|
|||||||
},
|
},
|
||||||
targetMessageId: entry.message.id,
|
targetMessageId: entry.message.id,
|
||||||
preload: preload,
|
preload: preload,
|
||||||
hasLike: hasLike
|
hasLike: hasLike,
|
||||||
|
isMy: false//!entry.message.effectivelyIncoming(context.account.peerId)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
return StoryContentItemSlice(
|
return StoryContentItemSlice(
|
||||||
|
|||||||
@ -9,8 +9,11 @@ import PhotoResources
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import UniversalMediaPlayer
|
import UniversalMediaPlayer
|
||||||
import TelegramUniversalVideoContent
|
import TelegramUniversalVideoContent
|
||||||
|
import StoryContainerScreen
|
||||||
|
|
||||||
final class StoryMessageContentComponent: Component {
|
final class StoryMessageContentComponent: Component {
|
||||||
|
typealias EnvironmentType = StoryContentItem.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let message: EngineMessage
|
let message: EngineMessage
|
||||||
|
|
||||||
@ -88,6 +91,11 @@ final class StoryMessageContentComponent: Component {
|
|||||||
|
|
||||||
private var component: StoryMessageContentComponent?
|
private var component: StoryMessageContentComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
|
private var environment: StoryContentItem.Environment?
|
||||||
|
|
||||||
|
private var currentProgressStart: Double?
|
||||||
|
private var currentProgressTimer: SwiftSignalKit.Timer?
|
||||||
|
private var videoProgressDisposable: Disposable?
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.imageNode = TransformImageNode()
|
self.imageNode = TransformImageNode()
|
||||||
@ -103,6 +111,8 @@ final class StoryMessageContentComponent: Component {
|
|||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.fetchDisposable?.dispose()
|
self.fetchDisposable?.dispose()
|
||||||
|
self.currentProgressTimer?.invalidate()
|
||||||
|
self.videoProgressDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func performActionAfterImageContentLoaded(update: Bool) {
|
private func performActionAfterImageContentLoaded(update: Bool) {
|
||||||
@ -149,9 +159,10 @@ final class StoryMessageContentComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(component: StoryMessageContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(component: StoryMessageContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<StoryContentItem.Environment>, transition: Transition) -> CGSize {
|
||||||
self.component = component
|
self.component = component
|
||||||
self.state = state
|
self.state = state
|
||||||
|
self.environment = environment[StoryContentItem.Environment.self].value
|
||||||
|
|
||||||
var messageMedia: EngineMedia?
|
var messageMedia: EngineMedia?
|
||||||
for media in component.message.media {
|
for media in component.message.media {
|
||||||
@ -266,6 +277,36 @@ final class StoryMessageContentComponent: Component {
|
|||||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: availableSize)
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let videoNode = self.videoNode {
|
||||||
|
if self.videoProgressDisposable == nil {
|
||||||
|
self.videoProgressDisposable = (videoNode.status
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
|
guard let self, let status, status.duration > 0.0 else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let currentProgress = Double(status.timestamp / status.duration)
|
||||||
|
let clippedProgress = max(0.0, min(1.0, currentProgress))
|
||||||
|
self.environment?.presentationProgressUpdated(clippedProgress)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if self.currentProgressTimer == nil {
|
||||||
|
self.currentProgressStart = CFAbsoluteTimeGetCurrent()
|
||||||
|
self.currentProgressTimer = SwiftSignalKit.Timer(
|
||||||
|
timeout: 1.0 / 60.0,
|
||||||
|
repeat: true,
|
||||||
|
completion: { [weak self] in
|
||||||
|
guard let self, let currentProgressStart = self.currentProgressStart else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let currentProgress = (CFAbsoluteTimeGetCurrent() - currentProgressStart) / 5.0
|
||||||
|
let clippedProgress = max(0.0, min(1.0, currentProgress))
|
||||||
|
self.environment?.presentationProgressUpdated(clippedProgress)
|
||||||
|
}, queue: .mainQueue())
|
||||||
|
self.currentProgressTimer?.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return availableSize
|
return availableSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,7 +315,7 @@ final class StoryMessageContentComponent: Component {
|
|||||||
return View(frame: CGRect())
|
return View(frame: CGRect())
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<StoryContentItem.Environment>, transition: Transition) -> CGSize {
|
||||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||||
|
|
||||||
|
swift_library(
|
||||||
|
name = "StoryFooterPanelComponent",
|
||||||
|
module_name = "StoryFooterPanelComponent",
|
||||||
|
srcs = glob([
|
||||||
|
"Sources/**/*.swift",
|
||||||
|
]),
|
||||||
|
copts = [
|
||||||
|
"-warnings-as-errors",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
"//submodules/Display",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/AppBundle",
|
||||||
|
"//submodules/Components/BundleIconComponent",
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
)
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import ComponentFlow
|
||||||
|
import AppBundle
|
||||||
|
import BundleIconComponent
|
||||||
|
|
||||||
|
public final class StoryFooterPanelComponent: Component {
|
||||||
|
public init(
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: StoryFooterPanelComponent, rhs: StoryFooterPanelComponent) -> Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class View: UIView {
|
||||||
|
private let viewStatsText = ComponentView<Empty>()
|
||||||
|
private let deleteButton = ComponentView<Empty>()
|
||||||
|
private let moreButton = ComponentView<Empty>()
|
||||||
|
|
||||||
|
private var component: StoryFooterPanelComponent?
|
||||||
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: StoryFooterPanelComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
let baseHeight: CGFloat = 44.0
|
||||||
|
let size = CGSize(width: availableSize.width, height: baseHeight)
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -193,7 +193,7 @@ private final class AttachmentFileContext: AttachmentMediaPickerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AttachmentFileControllerImpl: ItemListController, AttachmentContainable {
|
class AttachmentFileControllerImpl: ItemListController, AttachmentFileController, AttachmentContainable {
|
||||||
public var requestAttachmentMenuExpansion: () -> Void = {}
|
public var requestAttachmentMenuExpansion: () -> Void = {}
|
||||||
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
|
public var updateNavigationStack: (@escaping ([AttachmentContainable]) -> ([AttachmentContainable], AttachmentMediaPickerContext?)) -> Void = { _ in }
|
||||||
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
public var updateTabBarAlpha: (CGFloat, ContainedViewLayoutTransition) -> Void = { _, _ in }
|
||||||
@ -224,7 +224,7 @@ private struct AttachmentFileControllerState: Equatable {
|
|||||||
var searching: Bool
|
var searching: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileControllerImpl {
|
func makeAttachmentFileControllerImpl(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController {
|
||||||
let actionsDisposable = DisposableSet()
|
let actionsDisposable = DisposableSet()
|
||||||
|
|
||||||
let statePromise = ValuePromise(AttachmentFileControllerState(searching: false), ignoreRepeated: true)
|
let statePromise = ValuePromise(AttachmentFileControllerState(searching: false), ignoreRepeated: true)
|
||||||
|
|||||||
@ -90,6 +90,9 @@ import FeaturedStickersScreen
|
|||||||
import ChatEntityKeyboardInputNode
|
import ChatEntityKeyboardInputNode
|
||||||
import StorageUsageScreen
|
import StorageUsageScreen
|
||||||
import AvatarEditorScreen
|
import AvatarEditorScreen
|
||||||
|
import ChatScheduleTimeController
|
||||||
|
import ICloudResources
|
||||||
|
import LegacyCamera
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
import os.signpost
|
import os.signpost
|
||||||
@ -12670,105 +12673,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func getCaptionPanelView() -> TGCaptionPanelView {
|
private func getCaptionPanelView() -> TGCaptionPanelView? {
|
||||||
let presentationData = self.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
return self.context.sharedContext.makeGalleryCaptionPanelView(context: self.context, chatLocation: self.presentationInterfaceState.chatLocation, customEmojiAvailable: self.presentationInterfaceState.customEmojiAvailable, present: { [weak self] c in
|
||||||
var presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: presentationData.chatFontSize, bubbleCorners: presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: self.presentationInterfaceState.chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
|
self?.present(c, in: .window(.root))
|
||||||
|
}, presentInGlobalOverlay: { [weak self] c in
|
||||||
var updateChatPresentationInterfaceStateImpl: (((ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void)?
|
guard let self else {
|
||||||
var ensureFocusedImpl: (() -> Void)?
|
return
|
||||||
|
|
||||||
let interfaceInteraction = ChatPanelInterfaceInteraction(updateTextInputStateAndMode: { f in
|
|
||||||
updateChatPresentationInterfaceStateImpl?({
|
|
||||||
let (updatedState, updatedMode) = f($0.interfaceState.effectiveInputState, $0.inputMode)
|
|
||||||
return $0.updatedInterfaceState { interfaceState in
|
|
||||||
return interfaceState.withUpdatedEffectiveInputState(updatedState)
|
|
||||||
}.updatedInputMode({ _ in updatedMode })
|
|
||||||
})
|
|
||||||
}, updateInputModeAndDismissedButtonKeyboardMessageId: { f in
|
|
||||||
updateChatPresentationInterfaceStateImpl?({
|
|
||||||
let (updatedInputMode, updatedClosedButtonKeyboardMessageId) = f($0)
|
|
||||||
return $0.updatedInputMode({ _ in return updatedInputMode }).updatedInterfaceState({
|
|
||||||
$0.withUpdatedMessageActionsState({ value in
|
|
||||||
var value = value
|
|
||||||
value.closedButtonKeyboardMessageId = updatedClosedButtonKeyboardMessageId
|
|
||||||
return value
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, openLinkEditing: { [weak self] in
|
|
||||||
if let strongSelf = self {
|
|
||||||
var selectionRange: Range<Int>?
|
|
||||||
var text: NSAttributedString?
|
|
||||||
var inputMode: ChatInputMode?
|
|
||||||
updateChatPresentationInterfaceStateImpl?({ state in
|
|
||||||
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
|
||||||
if let selectionRange = selectionRange {
|
|
||||||
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
|
||||||
}
|
|
||||||
inputMode = state.inputMode
|
|
||||||
return state
|
|
||||||
})
|
|
||||||
|
|
||||||
var link: String?
|
|
||||||
if let text {
|
|
||||||
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
|
||||||
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
|
||||||
link = linkAttribute.url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { link in
|
|
||||||
if let inputMode = inputMode, let selectionRange = selectionRange {
|
|
||||||
if let link = link {
|
|
||||||
updateChatPresentationInterfaceStateImpl?({
|
|
||||||
return $0.updatedInterfaceState({
|
|
||||||
$0.withUpdatedEffectiveInputState(chatTextInputAddLinkAttribute($0.effectiveInputState, selectionRange: selectionRange, url: link))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
ensureFocusedImpl?()
|
|
||||||
updateChatPresentationInterfaceStateImpl?({
|
|
||||||
return $0.updatedInputMode({ _ in return inputMode }).updatedInterfaceState({
|
|
||||||
$0.withUpdatedEffectiveInputState(ChatTextInputState(inputText: $0.effectiveInputState.inputText, selectionRange: selectionRange.endIndex ..< selectionRange.endIndex))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
strongSelf.present(controller, in: .window(.root))
|
|
||||||
}
|
}
|
||||||
})
|
self.presentInGlobalOverlay(c)
|
||||||
|
}) as? TGCaptionPanelView
|
||||||
let inputPanelNode = AttachmentTextInputPanelNode(context: self.context, presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { [weak self] c in
|
|
||||||
self?.presentInGlobalOverlay(c)
|
|
||||||
}, makeEntityInputView: { [weak self] in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return EntityInputView(context: strongSelf.context, isDark: true, areCustomEmojiEnabled: strongSelf.presentationInterfaceState.customEmojiAvailable)
|
|
||||||
})
|
|
||||||
inputPanelNode.interfaceInteraction = interfaceInteraction
|
|
||||||
inputPanelNode.effectivePresentationInterfaceState = {
|
|
||||||
return presentationInterfaceState
|
|
||||||
}
|
|
||||||
|
|
||||||
updateChatPresentationInterfaceStateImpl = { [weak inputPanelNode] f in
|
|
||||||
let updatedPresentationInterfaceState = f(presentationInterfaceState)
|
|
||||||
let updateInputTextState = presentationInterfaceState.interfaceState.effectiveInputState != updatedPresentationInterfaceState.interfaceState.effectiveInputState
|
|
||||||
|
|
||||||
presentationInterfaceState = updatedPresentationInterfaceState
|
|
||||||
|
|
||||||
if let inputPanelNode = inputPanelNode, updateInputTextState {
|
|
||||||
inputPanelNode.updateInputTextState(updatedPresentationInterfaceState.interfaceState.effectiveInputState, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ensureFocusedImpl = { [weak inputPanelNode] in
|
|
||||||
inputPanelNode?.ensureFocused()
|
|
||||||
}
|
|
||||||
|
|
||||||
return inputPanelNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openCamera(cameraView: TGAttachmentCameraView? = nil) {
|
private func openCamera(cameraView: TGAttachmentCameraView? = nil) {
|
||||||
@ -13234,7 +13147,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
controller.prepareForReuse()
|
controller.prepareForReuse()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = attachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, bannedSendMedia: bannedSendFiles, presentGallery: { [weak self, weak attachmentController] in
|
let controller = strongSelf.context.sharedContext.makeAttachmentFileController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, bannedSendMedia: bannedSendFiles, presentGallery: { [weak self, weak attachmentController] in
|
||||||
attachmentController?.dismiss(animated: true)
|
attachmentController?.dismiss(animated: true)
|
||||||
self?.presentFileGallery()
|
self?.presentFileGallery()
|
||||||
}, presentFiles: { [weak self, weak attachmentController] in
|
}, presentFiles: { [weak self, weak attachmentController] in
|
||||||
@ -13252,8 +13165,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
let _ = currentFilesController.swap(controller)
|
if let controller = controller as? AttachmentFileControllerImpl {
|
||||||
completion(controller, controller.mediaPickerContext)
|
let _ = currentFilesController.swap(controller)
|
||||||
|
completion(controller, controller.mediaPickerContext)
|
||||||
|
}
|
||||||
case .location:
|
case .location:
|
||||||
strongSelf.controllerNavigationDisposable.set(nil)
|
strongSelf.controllerNavigationDisposable.set(nil)
|
||||||
let existingController = currentLocationController.with { $0 }
|
let existingController = currentLocationController.with { $0 }
|
||||||
|
|||||||
@ -343,7 +343,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||||||
self.deactivateSearch()
|
self.deactivateSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
public var mediaPickerContext: AttachmentMediaPickerContext {
|
public var mediaPickerContext: AttachmentMediaPickerContext? {
|
||||||
return ContactsPickerContext(controller: self)
|
return ContactsPickerContext(controller: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import WallpaperResources
|
|||||||
import MediaResources
|
import MediaResources
|
||||||
import LocationUI
|
import LocationUI
|
||||||
import ChatInterfaceState
|
import ChatInterfaceState
|
||||||
|
import ICloudResources
|
||||||
|
|
||||||
private var telegramUIDeclaredEncodables: Void = {
|
private var telegramUIDeclaredEncodables: Void = {
|
||||||
declareEncodable(VideoLibraryMediaResource.self, f: { VideoLibraryMediaResource(decoder: $0) })
|
declareEncodable(VideoLibraryMediaResource.self, f: { VideoLibraryMediaResource(decoder: $0) })
|
||||||
|
|||||||
@ -31,6 +31,10 @@ import ChatControllerInteraction
|
|||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
import StorageUsageScreen
|
import StorageUsageScreen
|
||||||
import DebugSettingsUI
|
import DebugSettingsUI
|
||||||
|
import TextFormat
|
||||||
|
import ChatTextLinkEditUI
|
||||||
|
import AttachmentTextInputPanelNode
|
||||||
|
import ChatEntityKeyboardInputNode
|
||||||
|
|
||||||
private final class AccountUserInterfaceInUseContext {
|
private final class AccountUserInterfaceInUseContext {
|
||||||
let subscribers = Bag<(Bool) -> Void>()
|
let subscribers = Bag<(Bool) -> Void>()
|
||||||
@ -1610,6 +1614,107 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController {
|
||||||
|
return makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, bannedSendMedia: bannedSendMedia, presentGallery: presentGallery, presentFiles: presentFiles, send: send)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject? {
|
||||||
|
var presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||||
|
|
||||||
|
var presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: presentationData.chatFontSize, bubbleCorners: presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: .standard(previewing: false), chatLocation: chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
|
||||||
|
|
||||||
|
var updateChatPresentationInterfaceStateImpl: (((ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void)?
|
||||||
|
var ensureFocusedImpl: (() -> Void)?
|
||||||
|
|
||||||
|
let interfaceInteraction = ChatPanelInterfaceInteraction(updateTextInputStateAndMode: { f in
|
||||||
|
updateChatPresentationInterfaceStateImpl?({
|
||||||
|
let (updatedState, updatedMode) = f($0.interfaceState.effectiveInputState, $0.inputMode)
|
||||||
|
return $0.updatedInterfaceState { interfaceState in
|
||||||
|
return interfaceState.withUpdatedEffectiveInputState(updatedState)
|
||||||
|
}.updatedInputMode({ _ in updatedMode })
|
||||||
|
})
|
||||||
|
}, updateInputModeAndDismissedButtonKeyboardMessageId: { f in
|
||||||
|
updateChatPresentationInterfaceStateImpl?({
|
||||||
|
let (updatedInputMode, updatedClosedButtonKeyboardMessageId) = f($0)
|
||||||
|
return $0.updatedInputMode({ _ in return updatedInputMode }).updatedInterfaceState({
|
||||||
|
$0.withUpdatedMessageActionsState({ value in
|
||||||
|
var value = value
|
||||||
|
value.closedButtonKeyboardMessageId = updatedClosedButtonKeyboardMessageId
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, openLinkEditing: {
|
||||||
|
var selectionRange: Range<Int>?
|
||||||
|
var text: NSAttributedString?
|
||||||
|
var inputMode: ChatInputMode?
|
||||||
|
updateChatPresentationInterfaceStateImpl?({ state in
|
||||||
|
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||||
|
if let selectionRange = selectionRange {
|
||||||
|
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||||
|
}
|
||||||
|
inputMode = state.inputMode
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
|
||||||
|
var link: String?
|
||||||
|
if let text {
|
||||||
|
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||||
|
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||||
|
link = linkAttribute.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = chatTextLinkEditController(sharedContext: context.sharedContext, updatedPresentationData: (presentationData, .never()), account: context.account, text: text?.string ?? "", link: link, apply: { link in
|
||||||
|
if let inputMode = inputMode, let selectionRange = selectionRange {
|
||||||
|
if let link = link {
|
||||||
|
updateChatPresentationInterfaceStateImpl?({
|
||||||
|
return $0.updatedInterfaceState({
|
||||||
|
$0.withUpdatedEffectiveInputState(chatTextInputAddLinkAttribute($0.effectiveInputState, selectionRange: selectionRange, url: link))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ensureFocusedImpl?()
|
||||||
|
updateChatPresentationInterfaceStateImpl?({
|
||||||
|
return $0.updatedInputMode({ _ in return inputMode }).updatedInterfaceState({
|
||||||
|
$0.withUpdatedEffectiveInputState(ChatTextInputState(inputText: $0.effectiveInputState.inputText, selectionRange: selectionRange.endIndex ..< selectionRange.endIndex))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
present(controller)
|
||||||
|
})
|
||||||
|
|
||||||
|
let inputPanelNode = AttachmentTextInputPanelNode(context: context, presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { c in
|
||||||
|
presentInGlobalOverlay(c)
|
||||||
|
}, makeEntityInputView: {
|
||||||
|
return EntityInputView(context: context, isDark: true, areCustomEmojiEnabled: customEmojiAvailable)
|
||||||
|
})
|
||||||
|
inputPanelNode.interfaceInteraction = interfaceInteraction
|
||||||
|
inputPanelNode.effectivePresentationInterfaceState = {
|
||||||
|
return presentationInterfaceState
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChatPresentationInterfaceStateImpl = { [weak inputPanelNode] f in
|
||||||
|
let updatedPresentationInterfaceState = f(presentationInterfaceState)
|
||||||
|
let updateInputTextState = presentationInterfaceState.interfaceState.effectiveInputState != updatedPresentationInterfaceState.interfaceState.effectiveInputState
|
||||||
|
|
||||||
|
presentationInterfaceState = updatedPresentationInterfaceState
|
||||||
|
|
||||||
|
if let inputPanelNode = inputPanelNode, updateInputTextState {
|
||||||
|
inputPanelNode.updateInputTextState(updatedPresentationInterfaceState.interfaceState.effectiveInputState, animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureFocusedImpl = { [weak inputPanelNode] in
|
||||||
|
inputPanelNode?.ensureFocused()
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputPanelNode
|
||||||
|
}
|
||||||
|
|
||||||
public func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController {
|
public func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController {
|
||||||
let mappedSource: PremiumSource
|
let mappedSource: PremiumSource
|
||||||
switch source {
|
switch source {
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import ChatInterfaceState
|
|||||||
import WallpaperResources
|
import WallpaperResources
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import ICloudResources
|
||||||
|
|
||||||
func makeTelegramAccountAuxiliaryMethods(appDelegate: AppDelegate?) -> AccountAuxiliaryMethods {
|
func makeTelegramAccountAuxiliaryMethods(appDelegate: AppDelegate?) -> AccountAuxiliaryMethods {
|
||||||
return AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
return AccountAuxiliaryMethods(fetchResource: { account, resource, ranges, _ in
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import DebugSettingsUI
|
|||||||
import TabBarUI
|
import TabBarUI
|
||||||
import WallpaperBackgroundNode
|
import WallpaperBackgroundNode
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
|
import LegacyCamera
|
||||||
|
|
||||||
private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode {
|
private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode {
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user