mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Various fixes
This commit is contained in:
parent
86ee12c1c8
commit
71f367027d
@ -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";
|
||||
|
@ -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 {
|
||||
|
@ -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) }
|
||||
|
@ -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
|
||||
|
@ -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])
|
||||
|
@ -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()
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
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()
|
||||
willComplete(title, {
|
||||
updateState { current in
|
||||
var current = current
|
||||
current.creating = true
|
||||
return current
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}))
|
||||
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() })
|
||||
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,24 +507,23 @@ 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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}))
|
||||
|> 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
|
||||
}
|
||||
|
||||
if let text = text {
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
}))
|
||||
})
|
||||
})
|
||||
}
|
||||
}, changeProfilePhoto: {
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user