Various fixes

This commit is contained in:
Ilya Laktyushin 2023-01-18 19:44:24 +04:00
parent 86ee12c1c8
commit 71f367027d
17 changed files with 407 additions and 406 deletions

View File

@ -8686,13 +8686,14 @@ Sorry for the inconvenience.";
"RequestPeer.SelectionConfirmationTitle" = "Are you sure you want to send %1$@ to %2$@?";
"RequestPeer.SelectionConfirmationInviteText" = "This will also add %1$@ to %2$@.";
"RequestPeer.SelectionConfirmationInviteAdminText" = "This will also add %1$@ to %2$@ as an admin.";
"RequestPeer.SelectionConfirmationInviteWithRightsText" = "This will also add %1$@ to %2$@ with the following rights:\n\n%3$@";
"RequestPeer.SelectionConfirmationSend" = "Send";
"CreateGroup.PublicLinkTitle" = "SET A PUBLIC LINK";
"CreateGroup.PublicLinkInfo" = "You can use **a-z**, **0-9** and underscores. Minimum length is **5** characters.";
"Notification.RequestedPeer" = "You shared %@ with the bot.";
"Notification.RequestedPeer" = "You shared %1$@ with %2$@.";
"Conversation.ViewInChannel" = "View in Channel";
@ -8706,3 +8707,14 @@ Sorry for the inconvenience.";
"Conversation.Translation.Hide" = "Hide";
"Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list.";
"Conversation.Translation.TranslationBarHiddenText" = "Translation bar is now hidden for this channel.";
"AvatarEditor.Background" = "BACKGROUND";
"AvatarEditor.EmojiOrSticker" = "EMOJI OR STICKER";
"AvatarEditor.Emoji" = "EMOJI";
"AvatarEditor.Stickers" = "STICKERS";
"AvatarEditor.SwitchToEmoji" = "SWITCH TO EMOJI";
"AvatarEditor.SwitchToStickers" = "SWITCH TO STICKERS";
"AvatarEditor.SetVideo" = "Set Video";
"AvatarEditor.Set" = "Set";

View File

@ -98,7 +98,7 @@ public enum ChatInputMode: Equatable {
case none
case text
case media(mode: ChatMediaInputMode, expanded: ChatMediaInputExpanded?, focused: Bool)
case inputButtons
case inputButtons(persistent: Bool)
}
public enum ChatTitlePanelContext: Equatable, Comparable {

View File

@ -1077,9 +1077,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[816245886] = { return Api.messages.Stickers.parse_stickers($0) }
dict[-244016606] = { return Api.messages.Stickers.parse_stickersNotModified($0) }
dict[-1821037486] = { return Api.messages.TranscribedAudio.parse_transcribedAudio($0) }
dict[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) }
dict[870003448] = { return Api.messages.TranslatedText.parse_translateResult($0) }
dict[-1575684144] = { return Api.messages.TranslatedText.parse_translateResultText($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1042605427] = { return Api.payments.BankCardData.parse_bankCardData($0) }
dict[-1362048039] = { return Api.payments.ExportedInvoice.parse_exportedInvoice($0) }

View File

@ -1344,18 +1344,10 @@ public extension Api.messages {
}
public extension Api.messages {
enum TranslatedText: TypeConstructorDescription {
case translateNoResult
case translateResult(result: [Api.TextWithEntities])
case translateResultText(text: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .translateNoResult:
if boxed {
buffer.appendInt32(1741309751)
}
break
case .translateResult(let result):
if boxed {
buffer.appendInt32(870003448)
@ -1366,29 +1358,16 @@ public extension Api.messages {
item.serialize(buffer, true)
}
break
case .translateResultText(let text):
if boxed {
buffer.appendInt32(-1575684144)
}
serializeString(text, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .translateNoResult:
return ("translateNoResult", [])
case .translateResult(let result):
return ("translateResult", [("result", result as Any)])
case .translateResultText(let text):
return ("translateResultText", [("text", text as Any)])
}
}
public static func parse_translateNoResult(_ reader: BufferReader) -> TranslatedText? {
return Api.messages.TranslatedText.translateNoResult
}
public static func parse_translateResult(_ reader: BufferReader) -> TranslatedText? {
var _1: [Api.TextWithEntities]?
if let _ = reader.readInt32() {
@ -1402,12 +1381,65 @@ public extension Api.messages {
return nil
}
}
public static func parse_translateResultText(_ reader: BufferReader) -> TranslatedText? {
var _1: String?
_1 = parseString(reader)
}
}
public extension Api.messages {
enum VotesList: TypeConstructorDescription {
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .votesList(let flags, let count, let votes, let users, let nextOffset):
if boxed {
buffer.appendInt32(136574537)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(votes.count))
for item in votes {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .votesList(let flags, let count, let votes, 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)])
}
}
public static func parse_votesList(_ reader: BufferReader) -> VotesList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.MessageUserVote]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
let _c1 = _1 != nil
if _c1 {
return Api.messages.TranslatedText.translateResultText(text: _1!)
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
}
else {
return nil

View File

@ -1,67 +1,3 @@
public extension Api.messages {
enum VotesList: TypeConstructorDescription {
case votesList(flags: Int32, count: Int32, votes: [Api.MessageUserVote], users: [Api.User], nextOffset: String?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .votesList(let flags, let count, let votes, let users, let nextOffset):
if boxed {
buffer.appendInt32(136574537)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(count, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(votes.count))
for item in votes {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(users.count))
for item in users {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 0) != 0 {serializeString(nextOffset!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .votesList(let flags, let count, let votes, 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)])
}
}
public static func parse_votesList(_ reader: BufferReader) -> VotesList? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int32?
_2 = reader.readInt32()
var _3: [Api.MessageUserVote]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserVote.self)
}
var _4: [Api.User]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
var _5: String?
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.messages.VotesList.votesList(flags: _1!, count: _2!, votes: _3!, users: _4!, nextOffset: _5)
}
else {
return nil
}
}
}
}
public extension Api.payments {
enum BankCardData: TypeConstructorDescription {
case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl])

View File

@ -6736,6 +6736,22 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func togglePeerTranslations(flags: Int32, peer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-461589127)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
return (FunctionDescription(name: "messages.togglePeerTranslations", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.messages {
static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View File

@ -356,12 +356,16 @@ public extension TelegramEngine {
return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction)
}
public func translate(text: String, fromLang: String?, toLang: String) -> Signal<String?, NoError> {
return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang)
public func translate(text: String, toLang: String) -> Signal<String?, NoError> {
return _internal_translate(network: self.account.network, text: text, toLang: toLang)
}
public func translateMessages(messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, NoError> {
return _internal_translateMessages(postbox: self.account.postbox, network: self.account.network, messageIds: messageIds, toLang: toLang)
return _internal_translateMessages(account: self.account, messageIds: messageIds, toLang: toLang)
}
public func togglePeerMessagesTranslationHidden(peerId: EnginePeer.Id, hidden: Bool) -> Signal<Never, NoError> {
return _internal_togglePeerMessagesTranslationHidden(account: self.account, peerId: peerId, hidden: hidden)
}
public func transcribeAudio(messageId: MessageId) -> Signal<EngineAudioTranscriptionResult, NoError> {

View File

@ -4,7 +4,7 @@ import SwiftSignalKit
import TelegramApi
import MtProtoKit
func _internal_translate(network: Network, text: String, fromLang: String?, toLang: String) -> Signal<String?, NoError> {
func _internal_translate(network: Network, text: String, toLang: String) -> Signal<String?, NoError> {
var flags: Int32 = 0
flags |= (1 << 1)
@ -18,10 +18,6 @@ func _internal_translate(network: Network, text: String, fromLang: String?, toLa
return .complete()
}
switch result {
case .translateNoResult:
return .single(nil)
case let .translateResultText(text):
return .single(text)
case let .translateResult(results):
if case let .textWithEntities(text, _) = results.first {
return .single(text)
@ -32,11 +28,11 @@ func _internal_translate(network: Network, text: String, fromLang: String?, toLa
}
}
func _internal_translateMessages(postbox: Postbox, network: Network, messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, NoError> {
func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, NoError> {
guard let peerId = messageIds.first?.peerId else {
return .never()
}
return postbox.transaction { transaction -> Api.InputPeer? in
return account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<Void, NoError> in
@ -48,7 +44,7 @@ func _internal_translateMessages(postbox: Postbox, network: Network, messageIds:
flags |= (1 << 0)
let id: [Int32] = messageIds.map { $0.id }
return network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang))
return account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.TranslatedText?, NoError> in
return .single(nil)
@ -57,7 +53,7 @@ func _internal_translateMessages(postbox: Postbox, network: Network, messageIds:
guard let result = result, case let .translateResult(results) = result else {
return .complete()
}
return postbox.transaction { transaction in
return account.postbox.transaction { transaction in
var index = 0
for result in results {
let messageId = messageIds[index]
@ -79,6 +75,28 @@ func _internal_translateMessages(postbox: Postbox, network: Network, messageIds:
}
}
func _internal_togglePeerMessagesTranslationHidden(account: Account, peerId: EnginePeer.Id, hidden: Bool) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapToSignal { inputPeer -> Signal<Never, NoError> in
guard let inputPeer = inputPeer else {
return .never()
}
var flags: Int32 = 0
if hidden {
flags |= (1 << 0)
}
return account.network.request(Api.functions.messages.togglePeerTranslations(flags: flags, peer: inputPeer))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Bool?, NoError> in
return .single(nil)
}
|> ignoreValues
}
}
public enum EngineAudioTranscriptionResult {
case success
case error

View File

@ -834,8 +834,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
case .attachMenuBotAllowed:
attributedString = NSAttributedString(string: strings.Notification_BotWriteAllowed, font: titleFont, textColor: primaryTextColor)
case let .requestedPeer(_, peerId):
let botName = message.peers[message.id.peerId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""
let peerName = message.peers[peerId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""
attributedString = addAttributesToStringWithRanges(strings.Notification_RequestedPeer(peerName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, peerId)]))
attributedString = addAttributesToStringWithRanges(strings.Notification_RequestedPeer(peerName, botName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, peerId), (1, message.id.peerId)]))
case .unknown:
attributedString = nil
}

View File

@ -127,13 +127,13 @@ final class AvatarEditorScreenComponent: Component {
super.init()
if let initialFileId, let initialBackgroundColors {
let _ = context.engine.stickers.resolveInlineStickers(fileIds: [initialFileId])
|> map { [weak self] files in
let _ = (context.engine.stickers.resolveInlineStickers(fileIds: [initialFileId])
|> deliverOnMainQueue).start(next: { [weak self] files in
if let strongSelf = self, let file = files.values.first {
strongSelf.selectedFile = file
strongSelf.updated(transition: .immediate)
}
}
})
self.selectedBackground = .gradient(initialBackgroundColors.map { UInt32(bitPattern: $0) })
self.previousColor = self.selectedBackground
} else {
@ -227,9 +227,12 @@ final class AvatarEditorScreenComponent: Component {
}
private func updateData(_ data: KeyboardInputData) {
let wasEmpty = self.data == nil
self.data = data
self.state?.selectedFile = data.emoji.panelItemGroups.first?.items.first?.itemFile
if wasEmpty && self.state?.selectedFile == nil {
self.state?.selectedFile = data.emoji.panelItemGroups.first?.items.first?.itemFile
}
self.state?.updated(transition: .immediate)
let updateSearchQuery: (String, String) -> Void = { [weak self] rawQuery, languageCode in
@ -656,6 +659,7 @@ final class AvatarEditorScreenComponent: Component {
self.state = state
let environment = environment[ViewControllerComponentContainer.Environment.self].value
let strings = environment.strings
let controller = environment.controller
self.controller = {
@ -703,7 +707,7 @@ final class AvatarEditorScreenComponent: Component {
let navigationDoneButtonSize = self.navigationDoneButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(Text(text: "Set", font: Font.semibold(17.0), color: state.isSearchActive ? environment.theme.rootController.navigationBar.accentTextColor : .white)),
content: AnyComponent(Text(text: strings.AvatarEditor_Set, font: Font.semibold(17.0), color: state.isSearchActive ? environment.theme.rootController.navigationBar.accentTextColor : .white)),
action: { [weak self] in
guard let self else {
return
@ -723,8 +727,8 @@ final class AvatarEditorScreenComponent: Component {
}
self.backgroundColor = environment.theme.list.blocksBackgroundColor
self.backgroundContainerView.backgroundColor = environment.theme.list.plainBackgroundColor
self.keyboardContainerView.backgroundColor = environment.theme.list.plainBackgroundColor
self.backgroundContainerView.backgroundColor = environment.theme.list.itemBlocksBackgroundColor
self.keyboardContainerView.backgroundColor = environment.theme.list.itemBlocksBackgroundColor
self.panelSeparatorView.backgroundColor = environment.theme.list.itemPlainSeparatorColor
if self.dataDisposable == nil {
@ -845,7 +849,7 @@ final class AvatarEditorScreenComponent: Component {
transition: transition,
component: AnyComponent(MultilineTextComponent(
text: .markdown(
text: "Background".uppercased(), attributes: MarkdownAttributes(
text: strings.AvatarEditor_Background.uppercased(), attributes: MarkdownAttributes(
body: body,
bold: bold,
link: body,
@ -955,14 +959,14 @@ final class AvatarEditorScreenComponent: Component {
let keyboardSwitchTitle: String
if state.isSearchActive {
keyboardTitle = "Emoji or Sticker"
keyboardTitle = strings.AvatarEditor_EmojiOrSticker
keyboardSwitchTitle = " "
} else if state.keyboardContentId == AnyHashable("emoji") {
keyboardTitle = "Emoji"
keyboardSwitchTitle = "Switch to Stickers"
keyboardTitle = strings.AvatarEditor_Emoji
keyboardSwitchTitle = strings.AvatarEditor_SwitchToStickers
} else if state.keyboardContentId == AnyHashable("stickers") {
keyboardTitle = "Stickers"
keyboardSwitchTitle = "Switch to Emoji"
keyboardTitle = strings.AvatarEditor_Stickers
keyboardSwitchTitle = strings.AvatarEditor_SwitchToEmoji
} else {
keyboardTitle = " "
keyboardSwitchTitle = " "
@ -1136,7 +1140,7 @@ final class AvatarEditorScreenComponent: Component {
transition: transition,
component: AnyComponent(
SolidRoundedButtonComponent(
title: "Set Video",
title: strings.AvatarEditor_SetVideo,
theme: SolidRoundedButtonComponent.Theme(theme: environment.theme),
fontSize: 17.0,
height: 50.0,
@ -1175,7 +1179,7 @@ final class AvatarEditorScreenComponent: Component {
entity.scale = 3.3
var documentId: Int64 = 0
if case let .file(file) = entity.content {
if case let .file(file) = entity.content, !file.isCustomEmoji {
documentId = file.fileId.id
}

View File

@ -4155,11 +4155,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: peerType, hasContactSelector: false, createNewGroup: {
createNewGroupImpl?()
}))
controller.peerSelected = { [weak self, weak controller] peer, _ in
let presentConfirmation: (String, @escaping () -> Void) -> Void = { [weak self] peerName, completion in
guard let strongSelf = self else {
return
}
let peerName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
let attributedTitle: NSAttributedString?
let attributedText: NSAttributedString
@ -4180,12 +4181,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break
}
if let botAdminRights {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteWithRightsText(botName, peerName, stringForAdminRights(strings: strongSelf.presentationData.strings, adminRights: botAdminRights))
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
for range in stringWithRanges.ranges.prefix(2) {
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
if botAdminRights.rights.isEmpty {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteAdminText(botName, peerName)
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
for range in stringWithRanges.ranges.prefix(2) {
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
}
attributedText = formattedString
} else {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteWithRightsText(botName, peerName, stringForAdminRights(strings: strongSelf.presentationData.strings, adminRights: botAdminRights))
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
for range in stringWithRanges.ranges.prefix(2) {
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range)
}
attributedText = formattedString
}
attributedText = formattedString
} else {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteText(botName, peerName)
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
@ -4196,28 +4206,46 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationSend, action: { [weak controller] in
let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).start()
controller?.dismiss()
let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationSend, action: {
completion()
})])
strongSelf.present(controller, in: .window(.root))
}
controller.peerSelected = { [weak self, weak controller] peer, _ in
guard let strongSelf = self else {
return
}
let peerName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
presentConfirmation(peerName, {
let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).start()
controller?.dismiss()
})
}
createNewGroupImpl = { [weak controller] in
switch peerType {
case .user:
break
case let .group(group):
let createGroupController = createGroupControllerImpl(context: context, peerIds: peerId.flatMap { [$0] } ?? [], mode: .requestPeer(group), completion: { peerId, dismiss in
let createGroupController = createGroupControllerImpl(context: context, peerIds: peerId.flatMap { [$0] } ?? [], mode: .requestPeer(group), willComplete: { peerName, complete in
presentConfirmation(peerName, {
complete()
})
}, completion: { peerId, dismiss in
let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).start()
dismiss()
})
createGroupController.navigationPresentation = .modal
controller?.replace(with: createGroupController)
case let .channel(channel):
let createChannelController = createChannelController(context: context, mode: .requestPeer(channel), completion: { peerId, dismiss in
let createChannelController = createChannelController(context: context, mode: .requestPeer(channel), willComplete: { peerName, complete in
presentConfirmation(peerName, {
complete()
})
}, completion: { peerId, dismiss in
let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).start()
dismiss()
})
createChannelController.navigationPresentation = .modal
@ -11082,10 +11110,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var temporaryChatPresentationInterfaceState = f(self.presentationInterfaceState)
if self.presentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup || self.presentationInterfaceState.keyboardButtonsMessage?.id != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.id {
if let keyboardButtonsMessage = temporaryChatPresentationInterfaceState.keyboardButtonsMessage, let _ = keyboardButtonsMessage.visibleButtonKeyboardMarkup {
if let keyboardButtonsMessage = temporaryChatPresentationInterfaceState.keyboardButtonsMessage, let keyboardMarkup = keyboardButtonsMessage.visibleButtonKeyboardMarkup {
if self.presentationInterfaceState.interfaceState.editMessage == nil && self.presentationInterfaceState.interfaceState.composeInputState.inputText.length == 0 && keyboardButtonsMessage.id != temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.closedButtonKeyboardMessageId && keyboardButtonsMessage.id != temporaryChatPresentationInterfaceState.interfaceState.messageActionsState.dismissedButtonKeyboardMessageId && temporaryChatPresentationInterfaceState.botStartPayload == nil {
temporaryChatPresentationInterfaceState = temporaryChatPresentationInterfaceState.updatedInputMode({ _ in
return .inputButtons
return .inputButtons(persistent: keyboardMarkup.flags.contains(.persistent))
})
}

View File

@ -2567,7 +2567,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
case .none:
break
case .inputButtons:
if let peer = self.chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil {
if let peer = self.chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, self.chatPresentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup?.flags.contains(.persistent) == true {
} else {
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.none, state.keyboardButtonsMessage?.id ?? state.interfaceState.messageActionsState.closedButtonKeyboardMessageId)
@ -3041,7 +3041,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
if let peer = self.chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, case .inputButtons = self.chatPresentationInterfaceState.inputMode {
if let peer = self.chatPresentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, case .inputButtons = self.chatPresentationInterfaceState.inputMode, self.chatPresentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup?.flags.contains(.persistent) == true {
enableGesture = false
}

View File

@ -15,45 +15,15 @@ func inputNodeForChatPresentationIntefaceState(_ chatPresentationInterfaceState:
}
switch chatPresentationInterfaceState.inputMode {
case .media:
if "".isEmpty {
if let currentNode = currentNode as? ChatEntityKeyboardInputNode {
return currentNode
} else if let inputMediaNode = inputMediaNode {
return inputMediaNode
} else if let inputMediaNode = makeMediaInputNode() {
inputMediaNode.interfaceInteraction = interfaceInteraction
return inputMediaNode
} else {
return nil
}
if let currentNode = currentNode as? ChatEntityKeyboardInputNode {
return currentNode
} else if let inputMediaNode = inputMediaNode {
return inputMediaNode
} else if let inputMediaNode = makeMediaInputNode() {
inputMediaNode.interfaceInteraction = interfaceInteraction
return inputMediaNode
} else {
if let currentNode = currentNode as? ChatMediaInputNode {
return currentNode
} else if let inputMediaNode = inputMediaNode {
return inputMediaNode
} else {
var peerId: PeerId?
if case let .peer(id) = chatPresentationInterfaceState.chatLocation {
peerId = id
}
let inputNode = ChatMediaInputNode(context: context, peerId: peerId, chatLocation: chatPresentationInterfaceState.chatLocation, controllerInteraction: controllerInteraction, chatWallpaper: chatPresentationInterfaceState.chatWallpaper, theme: chatPresentationInterfaceState.theme, strings: chatPresentationInterfaceState.strings, fontSize: chatPresentationInterfaceState.fontSize, gifPaneIsActiveUpdated: { [weak interfaceInteraction] value in
if let interfaceInteraction = interfaceInteraction {
interfaceInteraction.updateInputModeAndDismissedButtonKeyboardMessageId { state in
if case let .media(_, expanded, focused) = state.inputMode {
if value {
return (.media(mode: .gif, expanded: expanded, focused: focused), nil)
} else {
return (.media(mode: .other, expanded: expanded, focused: focused), nil)
}
} else {
return (state.inputMode, nil)
}
}
}
})
inputNode.interfaceInteraction = interfaceInteraction
return inputNode
}
return nil
}
case .inputButtons:
if chatPresentationInterfaceState.forceInputCommandsHidden {

View File

@ -2970,9 +2970,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.dismissedEmojiSuggestionPosition = nil
if let presentationInterfaceState = self.presentationInterfaceState {
if let peer = presentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, presentationInterfaceState.keyboardButtonsMessage != nil {
if let peer = presentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, let keyboardButtonsMessage = presentationInterfaceState.keyboardButtonsMessage, let keyboardMarkup = keyboardButtonsMessage.visibleButtonKeyboardMarkup, keyboardMarkup.flags.contains(.persistent) {
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId { _ in
return (.inputButtons, nil)
return (.inputButtons(persistent: true), nil)
}
} else {
switch presentationInterfaceState.inputMode {
@ -3481,7 +3481,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
case .bot:
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.inputButtons, nil)
return (.inputButtons(persistent: state.keyboardButtonsMessage?.visibleButtonKeyboardMarkup?.flags.contains(.persistent) ?? false), nil)
})
}
case .commands:

View File

@ -211,8 +211,7 @@ public enum CreateChannelMode {
case requestPeer(ReplyMarkupButtonRequestPeerType.Channel)
}
public func createChannelController(context: AccountContext, mode: CreateChannelMode = .generic, completion: ((PeerId, @escaping () -> Void) -> Void)? = nil) -> ViewController {
public func createChannelController(context: AccountContext, mode: CreateChannelMode = .generic, willComplete: @escaping (String, @escaping () -> Void) -> Void = { _, complete in complete() }, completion: ((PeerId, @escaping () -> Void) -> Void)? = nil) -> ViewController {
let initialState = CreateChannelState(creating: false, editingName: ItemListAvatarAndNameInfoItemName.title(title: "", type: .channel), editingDescriptionText: "", avatar: nil)
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
@ -256,53 +255,55 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
}
if !creating && !title.isEmpty {
updateState { current in
var current = current
current.creating = true
return current
}
willComplete(title, {
updateState { current in
var current = current
current.creating = true
return current
}
endEditingImpl?()
actionsDisposable.add((context.engine.peers.createChannel(title: title, description: description.isEmpty ? nil : description)
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
updateState { current in
var current = current
current.creating = false
return current
endEditingImpl?()
actionsDisposable.add((context.engine.peers.createChannel(title: title, description: description.isEmpty ? nil : description)
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
updateState { current in
var current = current
current.creating = false
return current
}
}
}).start(next: { peerId in
let updatingAvatar = stateValue.with {
return $0.avatar
}
if let _ = updatingAvatar {
let _ = context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
}).start()
}
}
}).start(next: { peerId in
let updatingAvatar = stateValue.with {
return $0.avatar
}
if let _ = updatingAvatar {
let _ = context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
}).start()
}
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
replaceControllerImpl?(controller)
}, error: { error in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String?
switch error {
case .generic, .tooMuchLocationBasedGroups:
text = presentationData.strings.Login_UnknownError
case .tooMuchJoined:
pushControllerImpl?(oldChannelsController(context: context, intent: .create))
return
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
default:
text = nil
}
if let text = text {
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
let controller = channelVisibilityController(context: context, peerId: peerId, mode: .initialSetup, upgradedToSupergroup: { _, f in f() })
replaceControllerImpl?(controller)
}, error: { error in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String?
switch error {
case .generic, .tooMuchLocationBasedGroups:
text = presentationData.strings.Login_UnknownError
case .tooMuchJoined:
pushControllerImpl?(oldChannelsController(context: context, intent: .create))
return
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
default:
text = nil
}
if let text = text {
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
})
}
}, changeProfilePhoto: {
endEditingImpl?()
@ -506,25 +507,24 @@ public func createChannelController(context: AccountContext, mode: CreateChannel
})
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get())
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
let rightNavigationButton: ItemListNavigationButton
if state.creating {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: !state.editingName.composedTitle.isEmpty, action: {
arguments.done()
})
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChannelIntro_CreateChannel), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: CreateChannelEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: CreateChannelEntryTag.info)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
let rightNavigationButton: ItemListNavigationButton
if state.creating {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Next), style: .bold, enabled: !state.editingName.composedTitle.isEmpty, action: {
arguments.done()
})
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChannelIntro_CreateChannel), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: CreateChannelEntries(presentationData: presentationData, state: state), style: .blocks, focusItemTag: CreateChannelEntryTag.info)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(context: context, state: signal)
replaceControllerImpl = { [weak controller] value in
(controller?.navigationController as? NavigationController)?.replaceAllButRootController(value, animated: true)

View File

@ -530,7 +530,7 @@ private func createGroupEntries(presentationData: PresentationData, state: Creat
return entries
}
public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId], initialTitle: String? = nil, mode: CreateGroupMode = .generic, completion: ((PeerId, @escaping () -> Void) -> Void)? = nil) -> ViewController {
public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId], initialTitle: String? = nil, mode: CreateGroupMode = .generic, willComplete: @escaping (String, @escaping () -> Void) -> Void = { _, complete in complete() }, completion: ((PeerId, @escaping () -> Void) -> Void)? = nil) -> ViewController {
var location: PeerGeoLocation?
if case let .locatedGroup(latitude, longitude, address) = mode {
location = PeerGeoLocation(latitude: latitude, longitude: longitude, address: address ?? "")
@ -591,52 +591,26 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
}
if !creating && !title.isEmpty {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.GlobalAutoremoveTimeout())
|> deliverOnMainQueue).start(next: { maybeGlobalAutoremoveTimeout in
updateState { current in
var current = current
current.creating = true
return current
}
endEditingImpl?()
let globalAutoremoveTimeout: Int32 = maybeGlobalAutoremoveTimeout ?? 0
let autoremoveTimeout = stateValue.with({ $0 }).autoremoveTimeout ?? globalAutoremoveTimeout
let ttlPeriod: Int32? = autoremoveTimeout == 0 ? nil : autoremoveTimeout
var createSignal: Signal<PeerId?, CreateGroupError>
switch mode {
case .generic:
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds, ttlPeriod: ttlPeriod)
case .supergroup:
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|> map(Optional.init)
|> mapError { error -> CreateGroupError in
switch error {
case .generic:
return .generic
case .restricted:
return .restricted
case .tooMuchJoined:
return .tooMuchJoined
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
case let .serverProvided(error):
return .serverProvided(error)
}
}
case .locatedGroup:
guard let location = location else {
return
willComplete(title, {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Configuration.GlobalAutoremoveTimeout())
|> deliverOnMainQueue).start(next: { maybeGlobalAutoremoveTimeout in
updateState { current in
var current = current
current.creating = true
return current
}
endEditingImpl?()
createSignal = addressPromise.get()
|> castError(CreateGroupError.self)
|> mapToSignal { address -> Signal<PeerId?, CreateGroupError> in
guard let address = address else {
return .complete()
}
return context.engine.peers.createSupergroup(title: title, description: nil, location: (location.latitude, location.longitude, address))
let globalAutoremoveTimeout: Int32 = maybeGlobalAutoremoveTimeout ?? 0
let autoremoveTimeout = stateValue.with({ $0 }).autoremoveTimeout ?? globalAutoremoveTimeout
let ttlPeriod: Int32? = autoremoveTimeout == 0 ? nil : autoremoveTimeout
var createSignal: Signal<PeerId?, CreateGroupError>
switch mode {
case .generic:
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds, ttlPeriod: ttlPeriod)
case .supergroup:
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
|> map(Optional.init)
|> mapError { error -> CreateGroupError in
switch error {
@ -652,50 +626,18 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
return .serverProvided(error)
}
}
}
case let .requestPeer(group):
var isForum = false
if let isForumRequested = group.isForum, isForumRequested {
isForum = true
}
if isForum {
createSignal = context.engine.peers.createSupergroup(title: title, description: nil, isForum: true)
|> map(Optional.init)
|> mapError { error -> CreateGroupError in
switch error {
case .generic:
return .generic
case .restricted:
return .restricted
case .tooMuchJoined:
return .tooMuchJoined
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
case let .serverProvided(error):
return .serverProvided(error)
}
case .locatedGroup:
guard let location = location else {
return
}
if let publicLink, !publicLink.isEmpty {
createSignal = createSignal
|> mapToSignal { peerId in
if let peerId = peerId {
return context.engine.peers.updateAddressName(domain: .peer(peerId), name: publicLink)
|> mapError { _ in
return .generic
}
|> map { _ in
return peerId
}
} else {
return .fail(.generic)
}
createSignal = addressPromise.get()
|> castError(CreateGroupError.self)
|> mapToSignal { address -> Signal<PeerId?, CreateGroupError> in
guard let address = address else {
return .complete()
}
}
} else {
if let publicLink, !publicLink.isEmpty {
createSignal = context.engine.peers.createSupergroup(title: title, description: nil)
return context.engine.peers.createSupergroup(title: title, description: nil, location: (location.latitude, location.longitude, address))
|> map(Optional.init)
|> mapError { error -> CreateGroupError in
switch error {
@ -711,6 +653,33 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
return .serverProvided(error)
}
}
}
case let .requestPeer(group):
var isForum = false
if let isForumRequested = group.isForum, isForumRequested {
isForum = true
}
let createGroupSignal: (Bool) -> Signal<PeerId?, CreateGroupError> = { isForum in
return context.engine.peers.createSupergroup(title: title, description: nil, isForum: isForum)
|> map(Optional.init)
|> mapError { error -> CreateGroupError in
switch error {
case .generic:
return .generic
case .restricted:
return .restricted
case .tooMuchJoined:
return .tooMuchJoined
case .tooMuchLocationBasedGroups:
return .tooMuchLocationBasedGroups
case let .serverProvided(error):
return .serverProvided(error)
}
}
}
if let publicLink, !publicLink.isEmpty {
createSignal = createGroupSignal(isForum)
|> mapToSignal { peerId in
if let peerId = peerId {
return context.engine.peers.updateAddressName(domain: .peer(peerId), name: publicLink)
@ -724,82 +693,101 @@ public func createGroupControllerImpl(context: AccountContext, peerIds: [PeerId]
return .fail(.generic)
}
}
} else if isForum || group.userAdminRights != nil {
createSignal = createGroupSignal(isForum)
} else {
createSignal = context.engine.peers.createGroup(title: title, peerIds: peerIds, ttlPeriod: nil)
}
}
}
actionsDisposable.add((createSignal
|> mapToSignal { peerId -> Signal<PeerId?, CreateGroupError> in
guard let peerId = peerId else {
return .single(nil)
}
let updatingAvatar = stateValue.with {
return $0.avatar
}
if let _ = updatingAvatar {
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
})
|> ignoreValues
|> `catch` { _ -> Signal<Never, CreateGroupError> in
return .complete()
}
|> mapToSignal { _ -> Signal<PeerId?, CreateGroupError> in
}
|> then(.single(peerId))
} else {
return .single(peerId)
}
}
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
updateState { current in
var current = current
current.creating = false
return current
if group.userAdminRights?.rights.contains(.canBeAnonymous) == true {
createSignal = createSignal
|> mapToSignal { peerId in
if let peerId = peerId {
return context.engine.peers.updateChannelAdminRights(peerId: peerId, adminId: context.account.peerId, rights: TelegramChatAdminRights(rights: .canBeAnonymous), rank: nil)
|> mapError { _ in
return .generic
}
|> map { _ in
return peerId
}
} else {
return .fail(.generic)
}
}
}
}
}).start(next: { peerId in
if let peerId = peerId {
if let completion = completion {
completion(peerId, {
dismissImpl?()
actionsDisposable.add((createSignal
|> mapToSignal { peerId -> Signal<PeerId?, CreateGroupError> in
guard let peerId = peerId else {
return .single(nil)
}
let updatingAvatar = stateValue.with {
return $0.avatar
}
if let _ = updatingAvatar {
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: uploadedAvatar.get(), video: uploadedVideoAvatar?.0.get(), videoStartTimestamp: uploadedVideoAvatar?.1, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: context.account.postbox, resource: resource, representations: representations)
})
|> ignoreValues
|> `catch` { _ -> Signal<Never, CreateGroupError> in
return .complete()
}
|> mapToSignal { _ -> Signal<PeerId?, CreateGroupError> in
}
|> then(.single(peerId))
} else {
let controller = ChatControllerImpl(context: context, chatLocation: .peer(id: peerId))
replaceControllerImpl?(controller)
return .single(peerId)
}
}
}, error: { error in
if case .serverProvided = error {
return
}
|> deliverOnMainQueue
|> afterDisposed {
Queue.mainQueue().async {
updateState { current in
var current = current
current.creating = false
return current
}
}
}).start(next: { peerId in
if let peerId = peerId {
if let completion = completion {
completion(peerId, {
dismissImpl?()
})
} else {
let controller = ChatControllerImpl(context: context, chatLocation: .peer(id: peerId))
replaceControllerImpl?(controller)
}
}
}, error: { error in
if case .serverProvided = error {
return
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String?
switch error {
case .privacy:
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelMultipleError
case .generic:
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
case .tooMuchJoined:
pushImpl?(oldChannelsController(context: context, intent: .create))
return
case .tooMuchLocationBasedGroups:
text = presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch
default:
text = nil
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text: String?
switch error {
case .privacy:
text = presentationData.strings.Privacy_GroupsAndChannels_InviteToChannelMultipleError
case .generic:
text = presentationData.strings.Login_UnknownError
case .restricted:
text = presentationData.strings.Common_ActionNotAllowedError
case .tooMuchJoined:
pushImpl?(oldChannelsController(context: context, intent: .create))
return
case .tooMuchLocationBasedGroups:
text = presentationData.strings.CreateGroup_ErrorLocatedGroupsTooMuch
default:
text = nil
}
if let text = text {
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
if let text = text {
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}
}))
})
})
}
}, changeProfilePhoto: {

View File

@ -99,14 +99,11 @@ private final class TranslateScreenComponent: CombinedComponent {
super.init()
self.translationDisposable.set((context.engine.messages.translate(text: text, fromLang: fromLanguage, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in
self.translationDisposable.set((context.engine.messages.translate(text: text, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in
guard let strongSelf = self else {
return
}
strongSelf.translatedText = text
// if strongSelf.fromLanguage == nil {
// strongSelf.fromLanguage = result.detectedLanguage
// }
strongSelf.updated(transition: .immediate)
}, error: { error in
@ -127,14 +124,11 @@ private final class TranslateScreenComponent: CombinedComponent {
self.translatedText = nil
self.updated(transition: .immediate)
self.translationDisposable.set((self.context.engine.messages.translate(text: text, fromLang: fromLanguage, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in
self.translationDisposable.set((self.context.engine.messages.translate(text: text, toLang: toLanguage) |> deliverOnMainQueue).start(next: { [weak self] text in
guard let strongSelf = self else {
return
}
strongSelf.translatedText = text
// if strongSelf.fromLanguage == nil {
// strongSelf.fromLanguage = result.detectedLanguage
// }
strongSelf.updated(transition: .immediate)
}, error: { error in