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.SelectionConfirmationTitle" = "Are you sure you want to send %1$@ to %2$@?";
"RequestPeer.SelectionConfirmationInviteText" = "This will also add %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.SelectionConfirmationInviteWithRightsText" = "This will also add %1$@ to %2$@ with the following rights:\n\n%3$@";
"RequestPeer.SelectionConfirmationSend" = "Send"; "RequestPeer.SelectionConfirmationSend" = "Send";
"CreateGroup.PublicLinkTitle" = "SET A PUBLIC LINK"; "CreateGroup.PublicLinkTitle" = "SET A PUBLIC LINK";
"CreateGroup.PublicLinkInfo" = "You can use **a-z**, **0-9** and underscores. Minimum length is **5** characters."; "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"; "Conversation.ViewInChannel" = "View in Channel";
@ -8706,3 +8707,14 @@ Sorry for the inconvenience.";
"Conversation.Translation.Hide" = "Hide"; "Conversation.Translation.Hide" = "Hide";
"Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list."; "Conversation.Translation.AddedToDoNotTranslateText" = "**%@** is added to the Do Not Translate list.";
"Conversation.Translation.TranslationBarHiddenText" = "Translation bar is now hidden for this channel."; "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 none
case text case text
case media(mode: ChatMediaInputMode, expanded: ChatMediaInputExpanded?, focused: Bool) case media(mode: ChatMediaInputMode, expanded: ChatMediaInputExpanded?, focused: Bool)
case inputButtons case inputButtons(persistent: Bool)
} }
public enum ChatTitlePanelContext: Equatable, Comparable { 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[816245886] = { return Api.messages.Stickers.parse_stickers($0) }
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[1741309751] = { return Api.messages.TranslatedText.parse_translateNoResult($0) }
dict[870003448] = { return Api.messages.TranslatedText.parse_translateResult($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[136574537] = { 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) }

View File

@ -1344,18 +1344,10 @@ public extension Api.messages {
} }
public extension Api.messages { public extension Api.messages {
enum TranslatedText: TypeConstructorDescription { enum TranslatedText: TypeConstructorDescription {
case translateNoResult
case translateResult(result: [Api.TextWithEntities]) case translateResult(result: [Api.TextWithEntities])
case translateResultText(text: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .translateNoResult:
if boxed {
buffer.appendInt32(1741309751)
}
break
case .translateResult(let result): case .translateResult(let result):
if boxed { if boxed {
buffer.appendInt32(870003448) buffer.appendInt32(870003448)
@ -1366,29 +1358,16 @@ public extension Api.messages {
item.serialize(buffer, true) item.serialize(buffer, true)
} }
break break
case .translateResultText(let text):
if boxed {
buffer.appendInt32(-1575684144)
}
serializeString(text, buffer: buffer, boxed: false)
break
} }
} }
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .translateNoResult:
return ("translateNoResult", [])
case .translateResult(let result): case .translateResult(let result):
return ("translateResult", [("result", result as Any)]) 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? { public static func parse_translateResult(_ reader: BufferReader) -> TranslatedText? {
var _1: [Api.TextWithEntities]? var _1: [Api.TextWithEntities]?
if let _ = reader.readInt32() { if let _ = reader.readInt32() {
@ -1402,12 +1381,65 @@ public extension Api.messages {
return nil 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 let _c1 = _1 != nil
if _c1 { let _c2 = _2 != nil
return Api.messages.TranslatedText.translateResultText(text: _1!) 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 { else {
return nil 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 { public extension Api.payments {
enum BankCardData: TypeConstructorDescription { enum BankCardData: TypeConstructorDescription {
case bankCardData(title: String, openUrls: [Api.BankCardOpenUrl]) 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 { public extension Api.functions.messages {
static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { static func toggleStickerSets(flags: Int32, stickersets: [Api.InputStickerSet]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer() let buffer = Buffer()

View File

@ -356,12 +356,16 @@ public extension TelegramEngine {
return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction) return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction)
} }
public func translate(text: String, fromLang: String?, toLang: String) -> Signal<String?, NoError> { public func translate(text: String, toLang: String) -> Signal<String?, NoError> {
return _internal_translate(network: self.account.network, text: text, fromLang: fromLang, toLang: toLang) return _internal_translate(network: self.account.network, text: text, toLang: toLang)
} }
public func translateMessages(messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, NoError> { 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> { public func transcribeAudio(messageId: MessageId) -> Signal<EngineAudioTranscriptionResult, NoError> {

View File

@ -4,7 +4,7 @@ import SwiftSignalKit
import TelegramApi import TelegramApi
import MtProtoKit 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 var flags: Int32 = 0
flags |= (1 << 1) flags |= (1 << 1)
@ -18,10 +18,6 @@ func _internal_translate(network: Network, text: String, fromLang: String?, toLa
return .complete() return .complete()
} }
switch result { switch result {
case .translateNoResult:
return .single(nil)
case let .translateResultText(text):
return .single(text)
case let .translateResult(results): case let .translateResult(results):
if case let .textWithEntities(text, _) = results.first { if case let .textWithEntities(text, _) = results.first {
return .single(text) 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 { guard let peerId = messageIds.first?.peerId else {
return .never() return .never()
} }
return postbox.transaction { transaction -> Api.InputPeer? in return account.postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer) return transaction.getPeer(peerId).flatMap(apiInputPeer)
} }
|> mapToSignal { inputPeer -> Signal<Void, NoError> in |> mapToSignal { inputPeer -> Signal<Void, NoError> in
@ -48,7 +44,7 @@ func _internal_translateMessages(postbox: Postbox, network: Network, messageIds:
flags |= (1 << 0) flags |= (1 << 0)
let id: [Int32] = messageIds.map { $0.id } 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) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.messages.TranslatedText?, NoError> in |> `catch` { _ -> Signal<Api.messages.TranslatedText?, NoError> in
return .single(nil) 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 { guard let result = result, case let .translateResult(results) = result else {
return .complete() return .complete()
} }
return postbox.transaction { transaction in return account.postbox.transaction { transaction in
var index = 0 var index = 0
for result in results { for result in results {
let messageId = messageIds[index] 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 { public enum EngineAudioTranscriptionResult {
case success case success
case error case error

View File

@ -834,8 +834,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
case .attachMenuBotAllowed: case .attachMenuBotAllowed:
attributedString = NSAttributedString(string: strings.Notification_BotWriteAllowed, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: strings.Notification_BotWriteAllowed, font: titleFont, textColor: primaryTextColor)
case let .requestedPeer(_, peerId): 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) ?? "" 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: case .unknown:
attributedString = nil attributedString = nil
} }

View File

@ -127,13 +127,13 @@ final class AvatarEditorScreenComponent: Component {
super.init() super.init()
if let initialFileId, let initialBackgroundColors { if let initialFileId, let initialBackgroundColors {
let _ = context.engine.stickers.resolveInlineStickers(fileIds: [initialFileId]) let _ = (context.engine.stickers.resolveInlineStickers(fileIds: [initialFileId])
|> map { [weak self] files in |> deliverOnMainQueue).start(next: { [weak self] files in
if let strongSelf = self, let file = files.values.first { if let strongSelf = self, let file = files.values.first {
strongSelf.selectedFile = file strongSelf.selectedFile = file
strongSelf.updated(transition: .immediate) strongSelf.updated(transition: .immediate)
} }
} })
self.selectedBackground = .gradient(initialBackgroundColors.map { UInt32(bitPattern: $0) }) self.selectedBackground = .gradient(initialBackgroundColors.map { UInt32(bitPattern: $0) })
self.previousColor = self.selectedBackground self.previousColor = self.selectedBackground
} else { } else {
@ -227,9 +227,12 @@ final class AvatarEditorScreenComponent: Component {
} }
private func updateData(_ data: KeyboardInputData) { private func updateData(_ data: KeyboardInputData) {
let wasEmpty = self.data == nil
self.data = data 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) self.state?.updated(transition: .immediate)
let updateSearchQuery: (String, String) -> Void = { [weak self] rawQuery, languageCode in let updateSearchQuery: (String, String) -> Void = { [weak self] rawQuery, languageCode in
@ -656,6 +659,7 @@ final class AvatarEditorScreenComponent: Component {
self.state = state self.state = state
let environment = environment[ViewControllerComponentContainer.Environment.self].value let environment = environment[ViewControllerComponentContainer.Environment.self].value
let strings = environment.strings
let controller = environment.controller let controller = environment.controller
self.controller = { self.controller = {
@ -703,7 +707,7 @@ final class AvatarEditorScreenComponent: Component {
let navigationDoneButtonSize = self.navigationDoneButton.update( let navigationDoneButtonSize = self.navigationDoneButton.update(
transition: transition, transition: transition,
component: AnyComponent(Button( 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 action: { [weak self] in
guard let self else { guard let self else {
return return
@ -723,8 +727,8 @@ final class AvatarEditorScreenComponent: Component {
} }
self.backgroundColor = environment.theme.list.blocksBackgroundColor self.backgroundColor = environment.theme.list.blocksBackgroundColor
self.backgroundContainerView.backgroundColor = environment.theme.list.plainBackgroundColor self.backgroundContainerView.backgroundColor = environment.theme.list.itemBlocksBackgroundColor
self.keyboardContainerView.backgroundColor = environment.theme.list.plainBackgroundColor self.keyboardContainerView.backgroundColor = environment.theme.list.itemBlocksBackgroundColor
self.panelSeparatorView.backgroundColor = environment.theme.list.itemPlainSeparatorColor self.panelSeparatorView.backgroundColor = environment.theme.list.itemPlainSeparatorColor
if self.dataDisposable == nil { if self.dataDisposable == nil {
@ -845,7 +849,7 @@ final class AvatarEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
text: .markdown( text: .markdown(
text: "Background".uppercased(), attributes: MarkdownAttributes( text: strings.AvatarEditor_Background.uppercased(), attributes: MarkdownAttributes(
body: body, body: body,
bold: bold, bold: bold,
link: body, link: body,
@ -955,14 +959,14 @@ final class AvatarEditorScreenComponent: Component {
let keyboardSwitchTitle: String let keyboardSwitchTitle: String
if state.isSearchActive { if state.isSearchActive {
keyboardTitle = "Emoji or Sticker" keyboardTitle = strings.AvatarEditor_EmojiOrSticker
keyboardSwitchTitle = " " keyboardSwitchTitle = " "
} else if state.keyboardContentId == AnyHashable("emoji") { } else if state.keyboardContentId == AnyHashable("emoji") {
keyboardTitle = "Emoji" keyboardTitle = strings.AvatarEditor_Emoji
keyboardSwitchTitle = "Switch to Stickers" keyboardSwitchTitle = strings.AvatarEditor_SwitchToStickers
} else if state.keyboardContentId == AnyHashable("stickers") { } else if state.keyboardContentId == AnyHashable("stickers") {
keyboardTitle = "Stickers" keyboardTitle = strings.AvatarEditor_Stickers
keyboardSwitchTitle = "Switch to Emoji" keyboardSwitchTitle = strings.AvatarEditor_SwitchToEmoji
} else { } else {
keyboardTitle = " " keyboardTitle = " "
keyboardSwitchTitle = " " keyboardSwitchTitle = " "
@ -1136,7 +1140,7 @@ final class AvatarEditorScreenComponent: Component {
transition: transition, transition: transition,
component: AnyComponent( component: AnyComponent(
SolidRoundedButtonComponent( SolidRoundedButtonComponent(
title: "Set Video", title: strings.AvatarEditor_SetVideo,
theme: SolidRoundedButtonComponent.Theme(theme: environment.theme), theme: SolidRoundedButtonComponent.Theme(theme: environment.theme),
fontSize: 17.0, fontSize: 17.0,
height: 50.0, height: 50.0,
@ -1175,7 +1179,7 @@ final class AvatarEditorScreenComponent: Component {
entity.scale = 3.3 entity.scale = 3.3
var documentId: Int64 = 0 var documentId: Int64 = 0
if case let .file(file) = entity.content { if case let .file(file) = entity.content, !file.isCustomEmoji {
documentId = file.fileId.id 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: { let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: peerType, hasContactSelector: false, createNewGroup: {
createNewGroupImpl?() 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 { guard let strongSelf = self else {
return return
} }
let peerName = EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
let attributedTitle: NSAttributedString? let attributedTitle: NSAttributedString?
let attributedText: NSAttributedString let attributedText: NSAttributedString
@ -4180,12 +4181,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break break
} }
if let botAdminRights { if let botAdminRights {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteWithRightsText(botName, peerName, stringForAdminRights(strings: strongSelf.presentationData.strings, adminRights: botAdminRights)) if botAdminRights.rights.isEmpty {
let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center) let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteAdminText(botName, peerName)
for range in stringWithRanges.ranges.prefix(2) { let formattedString = NSMutableAttributedString(string: stringWithRanges.string, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
formattedString.addAttribute(.font, value: Font.semibold(13.0), range: range.range) 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 { } else {
let stringWithRanges = strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationInviteText(botName, peerName) 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) 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 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: {
let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).start()
controller?.dismiss() completion()
})]) })])
strongSelf.present(controller, in: .window(.root)) 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 createNewGroupImpl = { [weak controller] in
switch peerType { switch peerType {
case .user: case .user:
break break
case let .group(group): 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() let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).start()
dismiss() dismiss()
}) })
createGroupController.navigationPresentation = .modal createGroupController.navigationPresentation = .modal
controller?.replace(with: createGroupController) controller?.replace(with: createGroupController)
case let .channel(channel): 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() let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).start()
dismiss() dismiss()
}) })
createChannelController.navigationPresentation = .modal createChannelController.navigationPresentation = .modal
@ -11082,10 +11110,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var temporaryChatPresentationInterfaceState = f(self.presentationInterfaceState) var temporaryChatPresentationInterfaceState = f(self.presentationInterfaceState)
if self.presentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.visibleButtonKeyboardMarkup || self.presentationInterfaceState.keyboardButtonsMessage?.id != temporaryChatPresentationInterfaceState.keyboardButtonsMessage?.id { 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 { 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 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: case .none:
break break
case .inputButtons: 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 { } else {
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.none, state.keyboardButtonsMessage?.id ?? state.interfaceState.messageActionsState.closedButtonKeyboardMessageId) 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 enableGesture = false
} }

View File

@ -15,45 +15,15 @@ func inputNodeForChatPresentationIntefaceState(_ chatPresentationInterfaceState:
} }
switch chatPresentationInterfaceState.inputMode { switch chatPresentationInterfaceState.inputMode {
case .media: case .media:
if "".isEmpty { if let currentNode = currentNode as? ChatEntityKeyboardInputNode {
if let currentNode = currentNode as? ChatEntityKeyboardInputNode { return currentNode
return currentNode } else if let inputMediaNode = inputMediaNode {
} else if let inputMediaNode = inputMediaNode { return inputMediaNode
return inputMediaNode } else if let inputMediaNode = makeMediaInputNode() {
} else if let inputMediaNode = makeMediaInputNode() { inputMediaNode.interfaceInteraction = interfaceInteraction
inputMediaNode.interfaceInteraction = interfaceInteraction return inputMediaNode
return inputMediaNode
} else {
return nil
}
} else { } else {
if let currentNode = currentNode as? ChatMediaInputNode { return nil
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
}
} }
case .inputButtons: case .inputButtons:
if chatPresentationInterfaceState.forceInputCommandsHidden { if chatPresentationInterfaceState.forceInputCommandsHidden {

View File

@ -2970,9 +2970,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.dismissedEmojiSuggestionPosition = nil self.dismissedEmojiSuggestionPosition = nil
if let presentationInterfaceState = self.presentationInterfaceState { 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 self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId { _ in
return (.inputButtons, nil) return (.inputButtons(persistent: true), nil)
} }
} else { } else {
switch presentationInterfaceState.inputMode { switch presentationInterfaceState.inputMode {
@ -3481,7 +3481,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
case .bot: case .bot:
self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId({ state in
return (.inputButtons, nil) return (.inputButtons(persistent: state.keyboardButtonsMessage?.visibleButtonKeyboardMarkup?.flags.contains(.persistent) ?? false), nil)
}) })
} }
case .commands: case .commands:

View File

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

View File

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

View File

@ -99,14 +99,11 @@ private final class TranslateScreenComponent: CombinedComponent {
super.init() 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 { guard let strongSelf = self else {
return return
} }
strongSelf.translatedText = text strongSelf.translatedText = text
// if strongSelf.fromLanguage == nil {
// strongSelf.fromLanguage = result.detectedLanguage
// }
strongSelf.updated(transition: .immediate) strongSelf.updated(transition: .immediate)
}, error: { error in }, error: { error in
@ -127,14 +124,11 @@ private final class TranslateScreenComponent: CombinedComponent {
self.translatedText = nil self.translatedText = nil
self.updated(transition: .immediate) 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 { guard let strongSelf = self else {
return return
} }
strongSelf.translatedText = text strongSelf.translatedText = text
// if strongSelf.fromLanguage == nil {
// strongSelf.fromLanguage = result.detectedLanguage
// }
strongSelf.updated(transition: .immediate) strongSelf.updated(transition: .immediate)
}, error: { error in }, error: { error in