mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
b1ca18df4e
commit
6000760416
@ -8844,3 +8844,5 @@ Sorry for the inconvenience.";
|
||||
"EmojiInput.TrendingEmoji" = "TRENDING EMOJI";
|
||||
|
||||
"Chat.PlaceholderTextNotAllowed" = "Text not allowed";
|
||||
|
||||
"CallList.DeleteAll" = "Delete All";
|
||||
|
@ -39,7 +39,7 @@ private final class DeleteAllButtonNode: ASDisplayNode {
|
||||
self.buttonNode.addSubnode(self.titleNode)
|
||||
self.contentNode.contentNode.addSubnode(self.buttonNode)
|
||||
|
||||
self.titleNode.attributedText = NSAttributedString(string: presentationData.strings.Notification_Exceptions_DeleteAll, font: Font.regular(17.0), textColor: presentationData.theme.rootController.navigationBar.accentTextColor)
|
||||
self.titleNode.attributedText = NSAttributedString(string: presentationData.strings.CallList_DeleteAll, font: Font.regular(17.0), textColor: presentationData.theme.rootController.navigationBar.accentTextColor)
|
||||
|
||||
//self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
switch type {
|
||||
case TGAudioSessionTypePlayAndRecord, TGAudioSessionTypePlayAndRecordHeadphones:
|
||||
if legacyContext.sharedContext.currentMediaInputSettings.with({ $0 }).pauseMusicOnRecording {
|
||||
convertedType = .record(speaker: false)
|
||||
convertedType = .record(speaker: false, withOthers: false)
|
||||
} else {
|
||||
convertedType = .recordWithOthers
|
||||
}
|
||||
|
@ -333,7 +333,8 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
||||
UIColor(rgb: 0x5A6EEE),
|
||||
UIColor(rgb: 0x548DFF),
|
||||
UIColor(rgb: 0x54A3FF),
|
||||
UIColor(rgb: 0x54bdff)
|
||||
UIColor(rgb: 0x54bdff),
|
||||
UIColor(rgb: 0x71c8ff)
|
||||
]
|
||||
|
||||
i = 0
|
||||
|
@ -18,7 +18,7 @@ public enum ManagedAudioSessionType: Equatable {
|
||||
case ambient
|
||||
case play
|
||||
case playWithPossiblePortOverride
|
||||
case record(speaker: Bool)
|
||||
case record(speaker: Bool, withOthers: Bool)
|
||||
case voiceCall
|
||||
case videoCall
|
||||
case recordWithOthers
|
||||
@ -587,7 +587,14 @@ public final class ManagedAudioSession {
|
||||
index += 1
|
||||
}
|
||||
|
||||
let lastIsRecordWithOthers = self.holders.last?.audioSessionType == .recordWithOthers
|
||||
var lastIsRecordWithOthers = false
|
||||
if let lastHolder = self.holders.last {
|
||||
if case let .record(_, withOthers) = lastHolder.audioSessionType {
|
||||
lastIsRecordWithOthers = withOthers
|
||||
} else if case .recordWithOthers = lastHolder.audioSessionType {
|
||||
lastIsRecordWithOthers = true
|
||||
}
|
||||
}
|
||||
if !deactivating {
|
||||
if let activeIndex = activeIndex {
|
||||
var deactivate = false
|
||||
@ -896,13 +903,13 @@ public final class ManagedAudioSession {
|
||||
|
||||
if resetToBuiltin {
|
||||
var updatedType = type
|
||||
if case .record(false) = updatedType, self.isHeadsetPluggedInValue {
|
||||
updatedType = .record(speaker: true)
|
||||
if case .record(false, let withOthers) = updatedType, self.isHeadsetPluggedInValue {
|
||||
updatedType = .record(speaker: true, withOthers: withOthers)
|
||||
}
|
||||
switch updatedType {
|
||||
case .record(false):
|
||||
case .record(false, _):
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
|
||||
case .voiceCall, .playWithPossiblePortOverride, .record(true):
|
||||
case .voiceCall, .playWithPossiblePortOverride, .record(true, _):
|
||||
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
|
||||
if let routes = AVAudioSession.sharedInstance().availableInputs {
|
||||
var alreadySet = false
|
||||
|
@ -356,11 +356,11 @@ public extension TelegramEngine {
|
||||
return EngineMessageReactionListContext(account: self.account, message: message, reaction: reaction)
|
||||
}
|
||||
|
||||
public func translate(text: String, toLang: String) -> Signal<String?, NoError> {
|
||||
public func translate(text: String, toLang: String) -> Signal<String?, TranslationError> {
|
||||
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, TranslationError> {
|
||||
return _internal_translateMessages(account: self.account, messageIds: messageIds, toLang: toLang)
|
||||
}
|
||||
|
||||
|
@ -4,19 +4,36 @@ import SwiftSignalKit
|
||||
import TelegramApi
|
||||
import MtProtoKit
|
||||
|
||||
func _internal_translate(network: Network, text: String, toLang: String) -> Signal<String?, NoError> {
|
||||
public enum TranslationError {
|
||||
case generic
|
||||
case invalidMessageId
|
||||
case textIsEmpty
|
||||
case textTooLong
|
||||
case invalidLanguage
|
||||
case limitExceeded
|
||||
}
|
||||
|
||||
func _internal_translate(network: Network, text: String, toLang: String) -> Signal<String?, TranslationError> {
|
||||
var flags: Int32 = 0
|
||||
flags |= (1 << 1)
|
||||
|
||||
return network.request(Api.functions.messages.translateText(flags: flags, peer: nil, id: nil, text: [.textWithEntities(text: text, entities: [])], toLang: toLang))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.TranslatedText?, NoError> in
|
||||
return .single(nil)
|
||||
|> mapError { error -> TranslationError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription == "MSG_ID_INVALID" {
|
||||
return .invalidMessageId
|
||||
} else if error.errorDescription == "INPUT_TEXT_EMPTY" {
|
||||
return .textIsEmpty
|
||||
} else if error.errorDescription == "INPUT_TEXT_TOO_LONG" {
|
||||
return .textTooLong
|
||||
} else if error.errorDescription == "TO_LANG_INVALID" {
|
||||
return .invalidLanguage
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<String?, NoError> in
|
||||
guard let result = result else {
|
||||
return .complete()
|
||||
}
|
||||
|> mapToSignal { result -> Signal<String?, TranslationError> in
|
||||
switch result {
|
||||
case let .translateResult(results):
|
||||
if case let .textWithEntities(text, _) = results.first {
|
||||
@ -28,14 +45,15 @@ func _internal_translate(network: Network, text: String, toLang: String) -> Sign
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, NoError> {
|
||||
func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id], toLang: String) -> Signal<Void, TranslationError> {
|
||||
guard let peerId = messageIds.first?.peerId else {
|
||||
return .never()
|
||||
}
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> mapToSignal { inputPeer -> Signal<Void, NoError> in
|
||||
|> castError(TranslationError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<Void, TranslationError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .never()
|
||||
}
|
||||
@ -45,12 +63,23 @@ func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id
|
||||
|
||||
let id: [Int32] = messageIds.map { $0.id }
|
||||
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)
|
||||
|> mapError { error -> TranslationError in
|
||||
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
|
||||
return .limitExceeded
|
||||
} else if error.errorDescription == "MSG_ID_INVALID" {
|
||||
return .invalidMessageId
|
||||
} else if error.errorDescription == "INPUT_TEXT_EMPTY" {
|
||||
return .textIsEmpty
|
||||
} else if error.errorDescription == "INPUT_TEXT_TOO_LONG" {
|
||||
return .textTooLong
|
||||
} else if error.errorDescription == "TO_LANG_INVALID" {
|
||||
return .invalidLanguage
|
||||
} else {
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
guard let result = result, case let .translateResult(results) = result else {
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, TranslationError> in
|
||||
guard case let .translateResult(results) = result else {
|
||||
return .complete()
|
||||
}
|
||||
return account.postbox.transaction { transaction in
|
||||
@ -71,6 +100,7 @@ func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|> castError(TranslationError.self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,25 @@ enum AvatarBackground: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
var isLight: Bool {
|
||||
switch self {
|
||||
case let .gradient(colors):
|
||||
if colors.count == 1 {
|
||||
return UIColor(rgb: colors.first!).lightness > 0.99
|
||||
} else if colors.count == 2 {
|
||||
return UIColor(rgb: colors.first!).lightness > 0.99 || UIColor(rgb: colors.last!).lightness > 0.99
|
||||
} else {
|
||||
var lightCount = 0
|
||||
for color in colors {
|
||||
if UIColor(rgb: color).lightness > 0.99 {
|
||||
lightCount += 1
|
||||
}
|
||||
}
|
||||
return lightCount >= 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateImage(size: CGSize) -> UIImage {
|
||||
switch self {
|
||||
case let .gradient(colors):
|
||||
@ -314,30 +333,27 @@ final class AvatarEditorScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let hasPremium = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
guard case let .user(user) = peer else {
|
||||
return false
|
||||
}
|
||||
return user.isPremium
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let resultSignal = signal
|
||||
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
return combineLatest(
|
||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000),
|
||||
context.engine.stickers.availableReactions(),
|
||||
hasPremium
|
||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1),
|
||||
combineLatest(keywords.map { context.engine.stickers.searchStickers(query: $0.emoticons)
|
||||
|> map { items -> [FoundStickerItem] in
|
||||
return items.items
|
||||
}
|
||||
})
|
||||
)
|
||||
|> take(1)
|
||||
|> map { view, availableReactions, hasPremium -> [EmojiPagerContentComponent.ItemGroup] in
|
||||
var result: [(String, TelegramMediaFile?, String)] = []
|
||||
|> map { view, stickers -> [EmojiPagerContentComponent.ItemGroup] in
|
||||
let hasPremium = true
|
||||
|
||||
var emoji: [(String, TelegramMediaFile?, String)] = []
|
||||
|
||||
var existingEmoticons = Set<String>()
|
||||
var allEmoticons: [String: String] = [:]
|
||||
for keyword in keywords {
|
||||
for emoticon in keyword.emoticons {
|
||||
allEmoticons[emoticon] = keyword.keyword
|
||||
existingEmoticons.insert(emoticon)
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,9 +366,9 @@ final class AvatarEditorScreenComponent: Component {
|
||||
case let .CustomEmoji(_, _, alt, _):
|
||||
if !item.file.isPremiumEmoji || hasPremium {
|
||||
if !alt.isEmpty, let keyword = allEmoticons[alt] {
|
||||
result.append((alt, item.file, keyword))
|
||||
emoji.append((alt, item.file, keyword))
|
||||
} else if alt == query {
|
||||
result.append((alt, item.file, alt))
|
||||
emoji.append((alt, item.file, alt))
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -361,10 +377,10 @@ final class AvatarEditorScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
var items: [EmojiPagerContentComponent.Item] = []
|
||||
var emojiItems: [EmojiPagerContentComponent.Item] = []
|
||||
|
||||
var existingIds = Set<MediaId>()
|
||||
for item in result {
|
||||
for item in emoji {
|
||||
if let itemFile = item.1 {
|
||||
if existingIds.contains(itemFile.fileId) {
|
||||
continue
|
||||
@ -378,14 +394,38 @@ final class AvatarEditorScreenComponent: Component {
|
||||
icon: .none,
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
emojiItems.append(item)
|
||||
}
|
||||
}
|
||||
|
||||
return [EmojiPagerContentComponent.ItemGroup(
|
||||
var stickerItems: [EmojiPagerContentComponent.Item] = []
|
||||
for stickerResult in stickers {
|
||||
for sticker in stickerResult {
|
||||
if existingIds.contains(sticker.file.fileId) {
|
||||
continue
|
||||
}
|
||||
|
||||
existingIds.insert(sticker.file.fileId)
|
||||
let animationData = EntityKeyboardAnimationData(file: sticker.file)
|
||||
let item = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
content: .animation(animationData),
|
||||
itemFile: sticker.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: .none
|
||||
)
|
||||
stickerItems.append(item)
|
||||
}
|
||||
}
|
||||
|
||||
var result: [EmojiPagerContentComponent.ItemGroup] = []
|
||||
if !emojiItems.isEmpty {
|
||||
result.append(
|
||||
EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
groupId: "search",
|
||||
title: nil,
|
||||
groupId: "emoji",
|
||||
title: "Emoji",
|
||||
subtitle: nil,
|
||||
actionButtonTitle: nil,
|
||||
isFeatured: false,
|
||||
@ -395,8 +435,30 @@ final class AvatarEditorScreenComponent: Component {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
items: items
|
||||
)]
|
||||
items: emojiItems
|
||||
)
|
||||
)
|
||||
}
|
||||
if !stickerItems.isEmpty {
|
||||
result.append(
|
||||
EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
groupId: "stickers",
|
||||
title: "Stickers",
|
||||
subtitle: nil,
|
||||
actionButtonTitle: nil,
|
||||
isFeatured: false,
|
||||
isPremiumLocked: false,
|
||||
isEmbedded: false,
|
||||
hasClear: false,
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
items: stickerItems
|
||||
)
|
||||
)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,7 @@ final class ManagedAudioRecorderContext {
|
||||
|
||||
if self.audioSessionDisposable == nil {
|
||||
let queue = self.queue
|
||||
self.audioSessionDisposable = self.mediaManager.audioSession.push(audioSessionType: .record(speaker: self.beginWithTone), activate: { [weak self] state in
|
||||
self.audioSessionDisposable = self.mediaManager.audioSession.push(audioSessionType: .record(speaker: self.beginWithTone, withOthers: false), activate: { [weak self] state in
|
||||
queue.async {
|
||||
if let strongSelf = self, !strongSelf.paused {
|
||||
strongSelf.hasAudioSession = true
|
||||
|
@ -44,8 +44,6 @@ private struct GlobalControlOptions: OptionSet {
|
||||
static let seek = GlobalControlOptions(rawValue: 1 << 5)
|
||||
}
|
||||
|
||||
public var test: Double?
|
||||
|
||||
public final class MediaManagerImpl: NSObject, MediaManager {
|
||||
public static var globalAudioSession: ManagedAudioSession {
|
||||
return sharedAudioSession
|
||||
|
@ -144,6 +144,9 @@ public func translateMessageIds(context: AccountContext, messageIds: [EngineMess
|
||||
}
|
||||
}
|
||||
return context.engine.messages.translateMessages(messageIds: messageIdsToTranslate, toLang: toLang)
|
||||
|> `catch` { _ -> Signal<Void, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user