Various improvements

This commit is contained in:
Ilya Laktyushin 2022-06-05 17:25:10 +04:00
parent 699c703c94
commit b69a0b6b3d
16 changed files with 216 additions and 35 deletions

View File

@ -7692,3 +7692,5 @@ Sorry for the inconvenience.";
"Chat.AudioTranscriptionFeedbackTip" = "Thank you for your feedback."; "Chat.AudioTranscriptionFeedbackTip" = "Thank you for your feedback.";
"Message.AudioTranscription.ErrorEmpty" = "No speech detected"; "Message.AudioTranscription.ErrorEmpty" = "No speech detected";
"Message.AudioTranscription.ErrorTooLong" = "The audio is too long"; "Message.AudioTranscription.ErrorTooLong" = "The audio is too long";
"WebApp.SelectChat" = "Select Chat";

View File

@ -176,6 +176,23 @@ public enum ResolvedUrlSettingsSection {
case devices case devices
} }
public struct ResolvedBotChoosePeerTypes: OptionSet {
public var rawValue: UInt32
public init(rawValue: UInt32) {
self.rawValue = rawValue
}
public init() {
self.rawValue = 0
}
public static let users = ResolvedBotChoosePeerTypes(rawValue: 1)
public static let bots = ResolvedBotChoosePeerTypes(rawValue: 2)
public static let groups = ResolvedBotChoosePeerTypes(rawValue: 4)
public static let channels = ResolvedBotChoosePeerTypes(rawValue: 16)
}
public struct ResolvedBotAdminRights: OptionSet { public struct ResolvedBotAdminRights: OptionSet {
public var rawValue: UInt32 public var rawValue: UInt32
@ -263,7 +280,7 @@ public enum ResolvedUrl {
case settings(ResolvedUrlSettingsSection) case settings(ResolvedUrlSettingsSection)
case joinVoiceChat(PeerId, String?) case joinVoiceChat(PeerId, String?)
case importStickers case importStickers
case startAttach(peerId: PeerId, payload: String?) case startAttach(peerId: PeerId, payload: String?, choose: ResolvedBotChoosePeerTypes?)
case invoice(slug: String, invoice: TelegramMediaInvoice) case invoice(slug: String, invoice: TelegramMediaInvoice)
case premiumOffer(reference: String?) case premiumOffer(reference: String?)
} }

View File

@ -30,6 +30,10 @@ public struct ChatListNodePeersFilter: OptionSet {
public static let excludeChannels = ChatListNodePeersFilter(rawValue: 1 << 12) public static let excludeChannels = ChatListNodePeersFilter(rawValue: 1 << 12)
public static let onlyGroupsAndChannels = ChatListNodePeersFilter(rawValue: 1 << 13) public static let onlyGroupsAndChannels = ChatListNodePeersFilter(rawValue: 1 << 13)
public static let excludeGroups = ChatListNodePeersFilter(rawValue: 1 << 14)
public static let excludeUsers = ChatListNodePeersFilter(rawValue: 1 << 15)
public static let excludeBots = ChatListNodePeersFilter(rawValue: 1 << 16)
} }

View File

@ -997,7 +997,39 @@ public final class ChatListNode: ListView {
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false } guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false } guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false } guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
if let peer = peer.peer {
switch peer {
case let .user(user):
if user.botInfo != nil {
if filter.contains(.excludeBots) {
return false
}
} else {
if filter.contains(.excludeUsers) {
return false
}
}
case .legacyGroup:
if filter.contains(.excludeGroups) {
return false
}
case let .channel(channel):
switch channel.info {
case .broadcast:
if filter.contains(.excludeChannels) {
return false
}
case .group:
if filter.contains(.excludeGroups) {
return false
}
}
default:
break
}
}
if filter.contains(.onlyGroupsAndChannels) { if filter.contains(.onlyGroupsAndChannels) {
if case .channel = peer.chatMainPeer { if case .channel = peer.chatMainPeer {
} else if case .legacyGroup = peer.chatMainPeer { } else if case .legacyGroup = peer.chatMainPeer {

View File

@ -280,9 +280,9 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
case let .messageMediaGeoLive(_, geo, heading, period, proximityNotificationRadius): case let .messageMediaGeoLive(_, geo, heading, period, proximityNotificationRadius):
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period, liveProximityNotificationRadius: proximityNotificationRadius, heading: heading) let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period, liveProximityNotificationRadius: proximityNotificationRadius, heading: heading)
return (mediaMap, nil) return (mediaMap, nil)
case let .messageMediaDocument(_, document, ttlSeconds): case let .messageMediaDocument(flags, document, ttlSeconds):
if let document = document { if let document = document {
if let mediaFile = telegramMediaFileFromApiDocument(document) { if let mediaFile = telegramMediaFileFromApiDocument(document, noPremium: (flags & (1 << 3)) != 0) {
return (mediaFile, ttlSeconds) return (mediaFile, ttlSeconds)
} }
} else { } else {

View File

@ -141,11 +141,14 @@ func telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: Int32,
return (immediateThumbnailData, representations) return (immediateThumbnailData, representations)
} }
func telegramMediaFileFromApiDocument(_ document: Api.Document) -> TelegramMediaFile? { func telegramMediaFileFromApiDocument(_ document: Api.Document, noPremium: Bool = false) -> TelegramMediaFile? {
switch document { switch document {
case let .document(_, id, accessHash, fileReference, _, mimeType, size, thumbs, videoThumbs, dcId, attributes): case let .document(_, id, accessHash, fileReference, _, mimeType, size, thumbs, videoThumbs, dcId, attributes):
var parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes) var parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes)
parsedAttributes.append(.hintIsValidated) parsedAttributes.append(.hintIsValidated)
if noPremium {
parsedAttributes.append(.NoPremium)
}
let (immediateThumbnail, previewRepresentations) = telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: dcId, documentId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: thumbs ?? []) let (immediateThumbnail, previewRepresentations) = telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: dcId, documentId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: thumbs ?? [])

View File

@ -8,7 +8,7 @@ extension TelegramTheme {
convenience init(apiTheme: Api.Theme) { convenience init(apiTheme: Api.Theme) {
switch apiTheme { switch apiTheme {
case let .theme(flags, id, accessHash, slug, title, document, settings, emoticon, installCount): case let .theme(flags, id, accessHash, slug, title, document, settings, emoticon, installCount):
self.init(id: id, accessHash: accessHash, slug: slug, emoticon: emoticon, title: title, file: document.flatMap(telegramMediaFileFromApiDocument), settings: settings?.compactMap(TelegramThemeSettings.init(apiThemeSettings:)), isCreator: (flags & 1 << 0) != 0, isDefault: (flags & 1 << 1) != 0, installCount: installCount) self.init(id: id, accessHash: accessHash, slug: slug, emoticon: emoticon, title: title, file: document.flatMap { telegramMediaFileFromApiDocument($0) }, settings: settings?.compactMap(TelegramThemeSettings.init(apiThemeSettings:)), isCreator: (flags & 1 << 0) != 0, isDefault: (flags & 1 << 1) != 0, installCount: installCount)
} }
} }
} }

View File

@ -511,10 +511,6 @@ func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaF
attributes.append(.documentAttributeSticker(flags: flags, alt: displayText, stickerset: stickerSet, maskCoords: inputMaskCoords)) attributes.append(.documentAttributeSticker(flags: flags, alt: displayText, stickerset: stickerSet, maskCoords: inputMaskCoords))
case .HasLinkedStickers: case .HasLinkedStickers:
attributes.append(.documentAttributeHasStickers) attributes.append(.documentAttributeHasStickers)
case .hintFileIsLarge:
break
case .hintIsValidated:
break
case let .Video(duration, size, videoFlags): case let .Video(duration, size, videoFlags):
var flags: Int32 = 0 var flags: Int32 = 0
if videoFlags.contains(.instantRoundVideo) { if videoFlags.contains(.instantRoundVideo) {
@ -542,6 +538,12 @@ func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaF
waveformBuffer = Buffer(data: waveform) waveformBuffer = Buffer(data: waveform)
} }
attributes.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer)) attributes.append(.documentAttributeAudio(flags: flags, duration: Int32(duration), title: title, performer: performer, waveform: waveformBuffer))
case .hintFileIsLarge:
break
case .hintIsValidated:
break
case .NoPremium:
break
} }
} }
return attributes return attributes
@ -782,8 +784,8 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|> mapError { _ -> PendingMessageUploadError in return .generic } |> mapError { _ -> PendingMessageUploadError in return .generic }
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in |> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
switch result { switch result {
case let .messageMediaDocument(_, document, _): case let .messageMediaDocument(flags, document, _):
if let document = document, let mediaFile = telegramMediaFileFromApiDocument(document), let resource = mediaFile.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference { if let document = document, let mediaFile = telegramMediaFileFromApiDocument(document, noPremium: (flags & (1 << 3)) != 0), let resource = mediaFile.resource as? CloudDocumentMediaResource, let fileReference = resource.fileReference {
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil, query: nil), text), reuploadInfo: nil)), media: mediaFile) return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaDocument(flags: 0, id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: fileReference)), ttlSeconds: nil, query: nil), text), reuploadInfo: nil)), media: mediaFile)
} }
default: default:

View File

@ -162,9 +162,9 @@ public func standaloneUploadedFile(account: Account, peerId: PeerId, text: Strin
|> mapError { _ -> StandaloneUploadMediaError in return .generic } |> mapError { _ -> StandaloneUploadMediaError in return .generic }
|> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in |> mapToSignal { media -> Signal<StandaloneUploadMediaEvent, StandaloneUploadMediaError> in
switch media { switch media {
case let .messageMediaDocument(_, document, _): case let .messageMediaDocument(flags, document, _):
if let document = document { if let document = document {
if let mediaFile = telegramMediaFileFromApiDocument(document) { if let mediaFile = telegramMediaFileFromApiDocument(document, noPremium: (flags & (1 << 3)) != 0) {
return .single(.result(.media(.standalone(media: mediaFile)))) return .single(.result(.media(.standalone(media: mediaFile))))
} }
} }

View File

@ -214,8 +214,8 @@ private extension AvailableReactions.Reaction {
guard let effectAnimationFile = telegramMediaFileFromApiDocument(effectAnimation) else { guard let effectAnimationFile = telegramMediaFileFromApiDocument(effectAnimation) else {
return nil return nil
} }
let aroundAnimationFile = aroundAnimation.flatMap(telegramMediaFileFromApiDocument) let aroundAnimationFile = aroundAnimation.flatMap { telegramMediaFileFromApiDocument($0) }
let centerAnimationFile = centerIcon.flatMap(telegramMediaFileFromApiDocument) let centerAnimationFile = centerIcon.flatMap { telegramMediaFileFromApiDocument($0) }
let isEnabled = (flags & (1 << 0)) == 0 let isEnabled = (flags & (1 << 0)) == 0
let isPremium = (flags & (1 << 2)) != 0 let isPremium = (flags & (1 << 2)) != 0
self.init( self.init(

View File

@ -542,6 +542,8 @@ private func decryptedAttributes46(_ attributes: [TelegramMediaFileAttribute], t
break break
case .hintIsValidated: case .hintIsValidated:
break break
case .NoPremium:
break
} }
} }
return result return result
@ -601,6 +603,8 @@ private func decryptedAttributes73(_ attributes: [TelegramMediaFileAttribute], t
break break
case .hintIsValidated: case .hintIsValidated:
break break
case .NoPremium:
break
} }
} }
return result return result
@ -660,6 +664,8 @@ private func decryptedAttributes101(_ attributes: [TelegramMediaFileAttribute],
break break
case .hintIsValidated: case .hintIsValidated:
break break
case .NoPremium:
break
} }
} }
return result return result

View File

@ -10,6 +10,7 @@ private let typeAudio: Int32 = 5
private let typeHasLinkedStickers: Int32 = 6 private let typeHasLinkedStickers: Int32 = 6
private let typeHintFileIsLarge: Int32 = 7 private let typeHintFileIsLarge: Int32 = 7
private let typeHintIsValidated: Int32 = 8 private let typeHintIsValidated: Int32 = 8
private let typeNoPremium: Int32 = 9
public enum StickerPackReference: PostboxCoding, Hashable, Equatable { public enum StickerPackReference: PostboxCoding, Hashable, Equatable {
case id(id: Int64, accessHash: Int64) case id(id: Int64, accessHash: Int64)
@ -144,6 +145,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
case HasLinkedStickers case HasLinkedStickers
case hintFileIsLarge case hintFileIsLarge
case hintIsValidated case hintIsValidated
case NoPremium
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0) let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0)
@ -171,6 +173,8 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
self = .hintFileIsLarge self = .hintFileIsLarge
case typeHintIsValidated: case typeHintIsValidated:
self = .hintIsValidated self = .hintIsValidated
case typeNoPremium:
self = .NoPremium
default: default:
preconditionFailure() preconditionFailure()
} }
@ -225,6 +229,8 @@ public enum TelegramMediaFileAttribute: PostboxCoding {
encoder.encodeInt32(typeHintFileIsLarge, forKey: "t") encoder.encodeInt32(typeHintFileIsLarge, forKey: "t")
case .hintIsValidated: case .hintIsValidated:
encoder.encodeInt32(typeHintIsValidated, forKey: "t") encoder.encodeInt32(typeHintIsValidated, forKey: "t")
case .NoPremium:
encoder.encodeInt32(typeNoPremium, forKey: "t")
} }
} }
} }

View File

@ -10778,11 +10778,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
return return
} }
if botId != nil && peer.id.namespace != Namespaces.Peer.CloudUser {
return
}
let context = self.context let context = self.context
let inputIsActive = self.presentationInterfaceState.inputMode == .text let inputIsActive = self.presentationInterfaceState.inputMode == .text

View File

@ -553,7 +553,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
present(controller, nil) present(controller, nil)
} }
} }
case let .startAttach(peerId, payload): case let .startAttach(peerId, payload, choose):
let presentError: (String) -> Void = { errorText in let presentError: (String) -> Void = { errorText in
present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: errorText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: errorText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in
return true return true
@ -561,23 +561,100 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
} }
let _ = (context.engine.messages.attachMenuBots() let _ = (context.engine.messages.attachMenuBots()
|> deliverOnMainQueue).start(next: { attachMenuBots in |> deliverOnMainQueue).start(next: { attachMenuBots in
if let _ = attachMenuBots.firstIndex(where: { $0.peer.id == peerId }) { func filterChooseTypes(_ chooseTypes: ResolvedBotChoosePeerTypes?, peerTypes: AttachMenuBots.Bot.PeerFlags) -> ResolvedBotChoosePeerTypes? {
if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { var chooseTypes = chooseTypes
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload), useExisting: true)) if chooseTypes != nil {
if !peerTypes.contains(.user) {
chooseTypes?.remove(.users)
}
if !peerTypes.contains(.bot) {
chooseTypes?.remove(.bots)
}
if !peerTypes.contains(.group) {
chooseTypes?.remove(.groups)
}
if !peerTypes.contains(.channel) {
chooseTypes?.remove(.channels)
}
}
return (chooseTypes?.isEmpty ?? true) ? nil : chooseTypes
}
if let bot = attachMenuBots.first(where: { $0.peer.id == peerId }) {
let choose = filterChooseTypes(choose, peerTypes: bot.peerTypes)
if let choose = choose {
var filters: ChatListNodePeersFilter = []
filters.insert(.onlyWriteable)
filters.insert(.excludeDisabled)
if !choose.contains(.users) {
filters.insert(.excludeUsers)
}
if !choose.contains(.bots) {
filters.insert(.excludeBots)
}
if !choose.contains(.groups) {
filters.insert(.excludeGroups)
}
if !choose.contains(.channels) {
filters.insert(.excludeChannels)
}
if let navigationController = navigationController {
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, filter: filters, hasChatListSelector: true, hasContactSelector: false, title: presentationData.strings.WebApp_SelectChat))
controller.peerSelected = { peer in
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: bot.peer.id, payload: payload), useExisting: true))
}
navigationController.pushViewController(controller)
}
} else { } else {
presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError) if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext {
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload), useExisting: true))
} else {
presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError)
}
} }
} else { } else {
let _ = (context.engine.messages.getAttachMenuBot(botId: peerId) let _ = (context.engine.messages.getAttachMenuBot(botId: peerId)
|> deliverOnMainQueue).start(next: { bot in |> deliverOnMainQueue).start(next: { bot in
let peer = EnginePeer(bot.peer) let choose = filterChooseTypes(choose, peerTypes: bot.peerTypes)
let controller = addWebAppToAttachmentController(context: context, peerName: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: {
let botPeer = EnginePeer(bot.peer)
let controller = addWebAppToAttachmentController(context: context, peerName: botPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), icons: bot.icons, completion: {
let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId) let _ = (context.engine.messages.addBotToAttachMenu(botId: peerId)
|> deliverOnMainQueue).start(error: { _ in |> deliverOnMainQueue).start(error: { _ in
presentError(presentationData.strings.WebApp_AddToAttachmentUnavailableError) presentError(presentationData.strings.WebApp_AddToAttachmentUnavailableError)
}, completed: { }, completed: {
if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { if let choose = choose {
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peer.id, payload: payload), useExisting: true)) var filters: ChatListNodePeersFilter = []
filters.insert(.onlyWriteable)
filters.insert(.excludeDisabled)
if !choose.contains(.users) {
filters.insert(.excludeUsers)
}
if !choose.contains(.bots) {
filters.insert(.excludeBots)
}
if !choose.contains(.groups) {
filters.insert(.excludeGroups)
}
if !choose.contains(.channels) {
filters.insert(.excludeChannels)
}
if let navigationController = navigationController {
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, filter: filters, hasChatListSelector: true, hasContactSelector: false, title: presentationData.strings.WebApp_SelectChat))
controller.peerSelected = { peer in
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload), useExisting: true))
}
navigationController.pushViewController(controller)
}
} else {
if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext {
let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: botPeer.id, payload: payload), useExisting: true))
}
} }
}) })
}) })

View File

@ -635,6 +635,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
var voiceChat: String? var voiceChat: String?
var attach: String? var attach: String?
var startAttach: String? var startAttach: String?
var choose: String?
if let queryItems = components.queryItems { if let queryItems = components.queryItems {
for queryItem in queryItems { for queryItem in queryItems {
if let value = queryItem.value { if let value = queryItem.value {
@ -658,6 +659,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
attach = value attach = value
} else if queryItem.name == "startattach" { } else if queryItem.name == "startattach" {
startAttach = value startAttach = value
} else if queryItem.name == "choose" {
choose = value
} }
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
voiceChat = "" voiceChat = ""
@ -697,6 +700,9 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} else { } else {
result += "?startattach" result += "?startattach"
} }
if let choose = choose {
result += "&choose=\(choose)"
}
} }
convertedUrl = result convertedUrl = result
} }

View File

@ -88,7 +88,7 @@ public enum ParsedInternalUrl {
case wallpaper(WallpaperUrlParameter) case wallpaper(WallpaperUrlParameter)
case theme(String) case theme(String)
case phone(String, String?, String?) case phone(String, String?, String?)
case startAttach(String, String?) case startAttach(String, String?, String?)
} }
private enum ParsedUrl { private enum ParsedUrl {
@ -210,12 +210,26 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(value)) return .peerName(peerName, .voiceChat(value))
} else if queryItem.name == "startattach" { } else if queryItem.name == "startattach" {
return .startAttach(peerName, value) var choose: String?
for queryItem in queryItems {
if queryItem.name == "choose", let value = queryItem.value {
choose = value
break
}
}
return .startAttach(peerName, value, choose)
} }
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(nil)) return .peerName(peerName, .voiceChat(nil))
} else if queryItem.name == "startattach" { } else if queryItem.name == "startattach" {
return .startAttach(peerName, nil) var choose: String?
for queryItem in queryItems {
if queryItem.name == "choose", let value = queryItem.value {
choose = value
break
}
}
return .startAttach(peerName, nil, choose)
} }
} }
} }
@ -591,7 +605,23 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
return .single(.wallpaper(parameter)) return .single(.wallpaper(parameter))
case let .theme(slug): case let .theme(slug):
return .single(.theme(slug)) return .single(.theme(slug))
case let .startAttach(name, payload): case let .startAttach(name, payload, chooseValue):
var choose: ResolvedBotChoosePeerTypes = []
if let chooseValue = chooseValue?.lowercased() {
let components = chooseValue.components(separatedBy: "+")
if components.contains("users") {
choose.insert(.users)
}
if components.contains("bots") {
choose.insert(.bots)
}
if components.contains("groups") {
choose.insert(.groups)
}
if components.contains("channels") {
choose.insert(.channels)
}
}
return context.engine.peers.resolvePeerByName(name: name) return context.engine.peers.resolvePeerByName(name: name)
|> take(1) |> take(1)
|> mapToSignal { peer -> Signal<Peer?, NoError> in |> mapToSignal { peer -> Signal<Peer?, NoError> in
@ -599,7 +629,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
} }
|> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in |> mapToSignal { peer -> Signal<ResolvedUrl?, NoError> in
if let peer = peer { if let peer = peer {
return .single(.startAttach(peerId: peer.id, payload: payload)) return .single(.startAttach(peerId: peer.id, payload: payload, choose: !choose.isEmpty ? choose : nil))
} else { } else {
return .single(.inaccessiblePeer) return .single(.inaccessiblePeer)
} }