Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2023-01-22 16:17:18 +04:00
commit bb536aec28
17 changed files with 179 additions and 96 deletions

View File

@ -299,7 +299,7 @@ public struct Transition {
} }
} }
public func attachAnimation(view: UIView, completion: @escaping (Bool) -> Void) { public func attachAnimation(view: UIView, id: String, completion: @escaping (Bool) -> Void) {
switch self.animation { switch self.animation {
case .none: case .none:
completion(true) completion(true)
@ -307,7 +307,7 @@ public struct Transition {
view.layer.animate( view.layer.animate(
from: 0.0 as NSNumber, from: 0.0 as NSNumber,
to: 1.0 as NSNumber, to: 1.0 as NSNumber,
keyPath: "attached\(UInt32.random(in: 0 ... UInt32.max))", keyPath: id,
duration: duration, duration: duration,
delay: 0.0, delay: 0.0,
curve: curve, curve: curve,

View File

@ -1205,7 +1205,7 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
let query = text.trimmingCharacters(in: .whitespacesAndNewlines) let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
if query.isSingleEmoji { if query.isSingleEmoji {
signals = .single([context.engine.stickers.searchStickers(query: text.basicEmoji.0) signals = .single([context.engine.stickers.searchStickers(query: text.basicEmoji.0)
|> map { (nil, $0) }]) |> map { (nil, $0.items) }])
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" { } else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3) var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
if !languageCode.lowercased().hasPrefix("en") { if !languageCode.lowercased().hasPrefix("en") {
@ -1228,7 +1228,7 @@ private final class FeaturedPaneSearchContentNode: ASDisplayNode {
for emoji in emoticons { for emoji in emoticons {
signals.append(context.engine.stickers.searchStickers(query: emoji.basicEmoji.0) signals.append(context.engine.stickers.searchStickers(query: emoji.basicEmoji.0)
|> take(1) |> take(1)
|> map { (emoji, $0) }) |> map { (emoji, $0.items) })
} }
return signals return signals
} }

View File

@ -523,12 +523,12 @@ let publicGroupRestrictedPermissions: TelegramChatBannedRightsFlags = [
] ]
func groupPermissionDependencies(_ right: TelegramChatBannedRightsFlags) -> TelegramChatBannedRightsFlags { func groupPermissionDependencies(_ right: TelegramChatBannedRightsFlags) -> TelegramChatBannedRightsFlags {
if right.contains(.banSendMedia) || banSendMediaSubList().contains(where: { $0.0 == right }) { if right.contains(.banEmbedLinks) {
return [.banSendText]
} else if right.contains(.banSendMedia) || banSendMediaSubList().contains(where: { $0.0 == right }) {
return [] return []
} else if right.contains(.banSendGifs) { } else if right.contains(.banSendGifs) {
return [] return []
} else if right.contains(.banEmbedLinks) {
return []
} else if right.contains(.banSendPolls) { } else if right.contains(.banSendPolls) {
return [] return []
} else if right.contains(.banChangeInfo) { } else if right.contains(.banChangeInfo) {
@ -762,6 +762,11 @@ public func channelPermissionsController(context: AccountContext, updatedPresent
effectiveRightsFlags.insert(right) effectiveRightsFlags.insert(right)
} }
} }
for (right, _) in banSendMediaSubList() {
if groupPermissionDependencies(right).contains(rights) {
effectiveRightsFlags.insert(right)
}
}
} }
} }
if banSendMediaSubList().allSatisfy({ !effectiveRightsFlags.contains($0.0) }) { if banSendMediaSubList().allSatisfy({ !effectiveRightsFlags.contains($0.0) }) {

View File

@ -7,16 +7,42 @@ private final class LinkHelperClass: NSObject {
} }
public extension TelegramGroup { public extension TelegramGroup {
enum Permission {
case sendSomething
}
func hasPermission(_ permission: Permission) -> Bool {
switch permission {
case .sendSomething:
let flags: TelegramChatBannedRightsFlags = [
.banSendText,
.banSendInstantVideos,
.banSendVoice,
.banSendPhotos,
.banSendVideos,
.banSendStickers,
.banSendPolls,
.banSendFiles,
.banSendInline
]
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.intersection(flags) == flags {
return false
}
return true
}
}
func hasBannedPermission(_ rights: TelegramChatBannedRightsFlags) -> Bool { func hasBannedPermission(_ rights: TelegramChatBannedRightsFlags) -> Bool {
switch self.role { switch self.role {
case .creator, .admin: case .creator, .admin:
return false
default:
if let bannedRights = self.defaultBannedRights {
return bannedRights.flags.contains(rights)
} else {
return false return false
default: }
if let bannedRights = self.defaultBannedRights {
return bannedRights.flags.contains(rights)
} else {
return false
}
} }
} }
} }

View File

@ -81,9 +81,9 @@ func _internal_randomGreetingSticker(account: Account) -> Signal<FoundStickerIte
} }
} }
func _internal_searchStickers(account: Account, query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<[FoundStickerItem], NoError> { func _internal_searchStickers(account: Account, query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
if scope.isEmpty { if scope.isEmpty {
return .single([]) return .single(([], true))
} }
var query = query var query = query
if query == "\u{2764}" { if query == "\u{2764}" {
@ -203,9 +203,10 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic
} }
return (result, cached, isPremium, searchStickersConfiguration) return (result, cached, isPremium, searchStickersConfiguration)
} |> mapToSignal { localItems, cached, isPremium, searchStickersConfiguration -> Signal<[FoundStickerItem], NoError> in }
|> mapToSignal { localItems, cached, isPremium, searchStickersConfiguration -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
if !scope.contains(.remote) { if !scope.contains(.remote) {
return .single(localItems) return .single((localItems, true))
} }
var tempResult: [FoundStickerItem] = [] var tempResult: [FoundStickerItem] = []
@ -281,8 +282,8 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic
|> `catch` { _ -> Signal<Api.messages.Stickers, NoError> in |> `catch` { _ -> Signal<Api.messages.Stickers, NoError> in
return .single(.stickersNotModified) return .single(.stickersNotModified)
} }
|> mapToSignal { result -> Signal<[FoundStickerItem], NoError> in |> mapToSignal { result -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> in
return account.postbox.transaction { transaction -> [FoundStickerItem] in return account.postbox.transaction { transaction -> (items: [FoundStickerItem], isFinalResult: Bool) in
switch result { switch result {
case let .stickers(hash, stickers): case let .stickers(hash, stickers):
var result: [FoundStickerItem] = [] var result: [FoundStickerItem] = []
@ -358,14 +359,14 @@ func _internal_searchStickers(account: Account, query: String, scope: SearchStic
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: entry) transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedStickerQueryResults, key: CachedStickerQueryResult.cacheKey(query)), entry: entry)
} }
return result return (result, true)
case .stickersNotModified: case .stickersNotModified:
break break
} }
return tempResult return (tempResult, true)
} }
} }
return .single(tempResult) return .single((tempResult, false))
|> then(remote) |> then(remote)
} }
} }

View File

@ -30,7 +30,7 @@ public extension TelegramEngine {
return _internal_randomGreetingSticker(account: self.account) return _internal_randomGreetingSticker(account: self.account)
} }
public func searchStickers(query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<[FoundStickerItem], NoError> { public func searchStickers(query: String, scope: SearchStickersScope = [.installed, .remote]) -> Signal<(items: [FoundStickerItem], isFinalResult: Bool), NoError> {
return _internal_searchStickers(account: self.account, query: query, scope: scope) return _internal_searchStickers(account: self.account, query: query, scope: scope)
} }

View File

@ -281,7 +281,11 @@ final class AvatarEditorScreenComponent: Component {
|> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in |> mapToSignal { keywords -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
return combineLatest( return combineLatest(
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: [], namespaces: [Namespaces.ItemCollection.CloudEmojiPacks], aroundIndex: nil, count: 10000000) |> take(1), 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.first!) }) combineLatest(keywords.map { context.engine.stickers.searchStickers(query: $0.emoticons.first!)
|> map { items -> [FoundStickerItem] in
return items.items
}
})
) )
|> map { view, stickers -> [EmojiPagerContentComponent.ItemGroup] in |> map { view, stickers -> [EmojiPagerContentComponent.ItemGroup] in
let hasPremium = true let hasPremium = true

View File

@ -1300,11 +1300,11 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
strongSelf.stickerSearchResult.set(.single(nil)) strongSelf.stickerSearchResult.set(.single(nil))
case let .category(value): case let .category(value):
let resultSignal = strongSelf.context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote]) let resultSignal = strongSelf.context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote])
|> mapToSignal { files -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in |> mapToSignal { files -> Signal<(items: [EmojiPagerContentComponent.ItemGroup], isFinalResult: Bool), NoError> in
var items: [EmojiPagerContentComponent.Item] = [] var items: [EmojiPagerContentComponent.Item] = []
var existingIds = Set<MediaId>() var existingIds = Set<MediaId>()
for item in files { for item in files.items {
let itemFile = item.file let itemFile = item.file
if existingIds.contains(itemFile.fileId) { if existingIds.contains(itemFile.fileId) {
continue continue
@ -1321,7 +1321,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
items.append(item) items.append(item)
} }
return .single([EmojiPagerContentComponent.ItemGroup( return .single(([EmojiPagerContentComponent.ItemGroup(
supergroupId: "search", supergroupId: "search",
groupId: "search", groupId: "search",
title: nil, title: nil,
@ -1335,7 +1335,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
displayPremiumBadges: false, displayPremiumBadges: false,
headerItem: nil, headerItem: nil,
items: items items: items
)]) )], files.isFinalResult))
} }
strongSelf.stickerSearchDisposable.set((resultSignal strongSelf.stickerSearchDisposable.set((resultSignal
@ -1343,7 +1343,13 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.stickerSearchResult.set(.single((result, AnyHashable(value)))) guard let group = result.items.first else {
return
}
if group.items.isEmpty && !result.isFinalResult {
return
}
strongSelf.stickerSearchResult.set(.single((result.items, AnyHashable(value))))
})) }))
} }
}, },

View File

@ -339,7 +339,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
let query = text.trimmingCharacters(in: .whitespacesAndNewlines) let query = text.trimmingCharacters(in: .whitespacesAndNewlines)
if query.isSingleEmoji { if query.isSingleEmoji {
signals = .single([context.engine.stickers.searchStickers(query: text.basicEmoji.0) signals = .single([context.engine.stickers.searchStickers(query: text.basicEmoji.0)
|> map { (nil, $0) }]) |> map { (nil, $0.items) }])
} else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" { } else if query.count > 1, let languageCode = languageCode, !languageCode.isEmpty && languageCode != "emoji" {
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3) var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
if !languageCode.lowercased().hasPrefix("en") { if !languageCode.lowercased().hasPrefix("en") {
@ -362,7 +362,7 @@ final class StickerPaneSearchContentNode: ASDisplayNode, PaneSearchContentNode {
for emoji in emoticons { for emoji in emoticons {
signals.append(context.engine.stickers.searchStickers(query: emoji.basicEmoji.0) signals.append(context.engine.stickers.searchStickers(query: emoji.basicEmoji.0)
// |> take(1) // |> take(1)
|> map { (emoji, $0) }) |> map { (emoji, $0.items) })
} }
return signals return signals
} }

View File

@ -5008,6 +5008,15 @@ public final class EmojiPagerContentComponent: Component {
scrollView.bounds = presentation.bounds scrollView.bounds = presentation.bounds
scrollView.layer.removeAllAnimations() scrollView.layer.removeAllAnimations()
} }
if self.isSearchActivated, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
scrollView.isScrollEnabled = false
DispatchQueue.main.async {
scrollView.isScrollEnabled = true
}
self.visibleSearchHeader?.deactivate()
}
self.component?.inputInteractionHolder.inputInteraction?.onScroll()
} }
public func ensureSearchUnfocused() { public func ensureSearchUnfocused() {
@ -5026,11 +5035,6 @@ public final class EmojiPagerContentComponent: Component {
self.updateVisibleItems(transition: .immediate, attemptSynchronousLoads: false, previousItemPositions: nil, updatedItemPositions: nil) self.updateVisibleItems(transition: .immediate, attemptSynchronousLoads: false, previousItemPositions: nil, updatedItemPositions: nil)
self.updateScrollingOffset(isReset: false, transition: .immediate) self.updateScrollingOffset(isReset: false, transition: .immediate)
if self.isSearchActivated, let visibleSearchHeader = self.visibleSearchHeader, visibleSearchHeader.currentPresetSearchTerm == nil {
self.visibleSearchHeader?.deactivate()
}
self.component?.inputInteractionHolder.inputInteraction?.onScroll()
} }
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
@ -6375,7 +6379,7 @@ public final class EmojiPagerContentComponent: Component {
} }
} }
} else { } else {
/*if component.inputInteractionHolder.inputInteraction?.externalBackground == nil { /*if useOpaqueTheme {
if visibleSearchHeader.superview != self.scrollView { if visibleSearchHeader.superview != self.scrollView {
self.scrollView.addSubview(visibleSearchHeader) self.scrollView.addSubview(visibleSearchHeader)
self.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView) self.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
@ -6431,7 +6435,7 @@ public final class EmojiPagerContentComponent: Component {
let searchHeaderFrame = CGRect(origin: CGPoint(x: itemLayout.searchInsets.left, y: itemLayout.searchInsets.top), size: CGSize(width: itemLayout.width - itemLayout.searchInsets.left - itemLayout.searchInsets.right, height: itemLayout.searchHeight)) let searchHeaderFrame = CGRect(origin: CGPoint(x: itemLayout.searchInsets.left, y: itemLayout.searchInsets.top), size: CGSize(width: itemLayout.width - itemLayout.searchInsets.left - itemLayout.searchInsets.right, height: itemLayout.searchHeight))
visibleSearchHeader.update(context: component.context, theme: keyboardChildEnvironment.theme, strings: keyboardChildEnvironment.strings, text: displaySearchWithPlaceholder, useOpaqueTheme: useOpaqueTheme, isActive: self.isSearchActivated, size: searchHeaderFrame.size, canFocus: !component.searchIsPlaceholderOnly, searchCategories: component.searchCategories, transition: transition) visibleSearchHeader.update(context: component.context, theme: keyboardChildEnvironment.theme, strings: keyboardChildEnvironment.strings, text: displaySearchWithPlaceholder, useOpaqueTheme: useOpaqueTheme, isActive: self.isSearchActivated, size: searchHeaderFrame.size, canFocus: !component.searchIsPlaceholderOnly, searchCategories: component.searchCategories, transition: transition)
transition.attachAnimation(view: visibleSearchHeader, completion: { [weak self] completed in /*transition.attachAnimation(view: visibleSearchHeader, id: "search_transition", completion: { [weak self] completed in
guard let strongSelf = self, completed, let visibleSearchHeader = strongSelf.visibleSearchHeader else { guard let strongSelf = self, completed, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
return return
} }
@ -6440,8 +6444,41 @@ public final class EmojiPagerContentComponent: Component {
strongSelf.scrollView.addSubview(visibleSearchHeader) strongSelf.scrollView.addSubview(visibleSearchHeader)
strongSelf.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView) strongSelf.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
} }
}) })*/
transition.setFrame(view: visibleSearchHeader, frame: searchHeaderFrame) if visibleSearchHeader.frame != searchHeaderFrame {
transition.setFrame(view: visibleSearchHeader, frame: searchHeaderFrame, completion: { [weak self] completed in
if !useOpaqueTheme {
guard let strongSelf = self, completed, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
return
}
if !strongSelf.isSearchActivated && visibleSearchHeader.superview != strongSelf.scrollView {
strongSelf.scrollView.addSubview(visibleSearchHeader)
strongSelf.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
}
}
})
// Temporary workaround for status selection; use a separate search container (see GIF)
if useOpaqueTheme {
if case let .curve(duration, _) = transition.animation, duration != 0.0 {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + duration, execute: { [weak self] in
guard let strongSelf = self, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
return
}
if !strongSelf.isSearchActivated && visibleSearchHeader.superview != strongSelf.scrollView {
strongSelf.scrollView.addSubview(visibleSearchHeader)
strongSelf.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
}
})
} else {
if !self.isSearchActivated && visibleSearchHeader.superview != self.scrollView {
self.scrollView.addSubview(visibleSearchHeader)
self.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
}
}
}
}
} else { } else {
if let visibleSearchHeader = self.visibleSearchHeader { if let visibleSearchHeader = self.visibleSearchHeader {
self.visibleSearchHeader = nil self.visibleSearchHeader = nil

View File

@ -288,6 +288,7 @@ final class EmojiSearchSearchBarComponent: Component {
component.searchTermUpdated(group.identifiers.joined(separator: "")) component.searchTermUpdated(group.identifiers.joined(separator: ""))
} else { } else {
component.searchTermUpdated(nil) component.searchTermUpdated(nil)
self.scrollView.setContentOffset(CGPoint(), animated: true)
} }
break break
@ -301,6 +302,7 @@ final class EmojiSearchSearchBarComponent: Component {
if self.selectedItem != nil { if self.selectedItem != nil {
self.selectedItem = nil self.selectedItem = nil
self.state?.updated(transition: .immediate) self.state?.updated(transition: .immediate)
self.scrollView.setContentOffset(CGPoint(), animated: true)
if dispatchEvent { if dispatchEvent {
self.component?.searchTermUpdated(nil) self.component?.searchTermUpdated(nil)
} }

View File

@ -447,10 +447,10 @@ final class DataUsageScreenComponent: Component {
headerOffset = min(headerOffset, minOffset) headerOffset = min(headerOffset, minOffset)
let animatedTransition = Transition(animation: .curve(duration: 0.18, curve: .easeInOut)) let animatedTransition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
let navigationBackgroundAlpha: CGFloat = abs(headerOffset - minOffset) < 4.0 ? 1.0 : 0.0 let navigationBackgroundAlpha: CGFloat = abs(headerOffset - minOffset) < 4.0 ? 1.0 : 0.0
let navigationButtonAlpha: CGFloat = abs(headerOffset - minOffset) < 62.0 ? 0.0 : 1.0 let navigationButtonAlpha: CGFloat = scrollBounds.minY >= navigationMetrics.navigationHeight ? 0.0 : 1.0
animatedTransition.setAlpha(view: self.navigationBackgroundView, alpha: navigationBackgroundAlpha) animatedTransition.setAlpha(view: self.navigationBackgroundView, alpha: navigationBackgroundAlpha)
animatedTransition.setAlpha(layer: self.navigationSeparatorLayerContainer, alpha: navigationBackgroundAlpha) animatedTransition.setAlpha(layer: self.navigationSeparatorLayerContainer, alpha: navigationBackgroundAlpha)
@ -468,17 +468,19 @@ final class DataUsageScreenComponent: Component {
transition.setBounds(view: self.headerOffsetContainer, bounds: CGRect(origin: CGPoint(x: 0.0, y: headerOffset), size: self.headerOffsetContainer.bounds.size)) transition.setBounds(view: self.headerOffsetContainer, bounds: CGRect(origin: CGPoint(x: 0.0, y: headerOffset), size: self.headerOffsetContainer.bounds.size))
if let controller = self.controller?(), let backButtonNode = controller.navigationBar?.backButtonNode { if let controller = self.controller?(), let backButtonNode = controller.navigationBar?.backButtonNode {
if backButtonNode.isHidden { if backButtonNode.alpha != navigationButtonAlpha {
backButtonNode.alpha = 0.0 if backButtonNode.isHidden {
backButtonNode.isHidden = false backButtonNode.alpha = 0.0
} backButtonNode.isHidden = false
animatedTransition.setAlpha(layer: backButtonNode.layer, alpha: navigationButtonAlpha, completion: { [weak backButtonNode] completed in
if let backButtonNode, completed {
if navigationButtonAlpha.isZero {
backButtonNode.isHidden = true
}
} }
}) animatedTransition.setAlpha(layer: backButtonNode.layer, alpha: navigationButtonAlpha, completion: { [weak backButtonNode] completed in
if let backButtonNode, completed {
if navigationButtonAlpha.isZero {
backButtonNode.isHidden = true
}
}
})
}
} }
} }
} }

View File

@ -18184,17 +18184,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var itemList: [String] = [] var itemList: [String] = []
var flags: TelegramChatBannedRightsFlags = []
if let channel = peer as? TelegramChannel {
if let bannedRights = channel.bannedRights {
flags = bannedRights.flags
}
} else if let group = peer as? TelegramGroup {
if let bannedRights = group.defaultBannedRights {
flags = bannedRights.flags
}
}
let order: [TelegramChatBannedRightsFlags] = [ let order: [TelegramChatBannedRightsFlags] = [
.banSendText, .banSendText,
.banSendPhotos, .banSendPhotos,
@ -18207,32 +18196,40 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
] ]
for right in order { for right in order {
if !flags.contains(right) { if let channel = peer as? TelegramChannel {
var title: String? if channel.hasBannedPermission(right) != nil {
switch right { continue
case .banSendText:
title = "text messages"
case .banSendPhotos:
title = "photos"
case .banSendVideos:
title = "videos"
case .banSendVoice:
title = "voice messages"
case .banSendInstantVideos:
title = "video messages"
case .banSendFiles:
title = "files"
case .banSendMusic:
title = "music"
case .banSendStickers:
title = "Stickers & GIFs"
default:
break
} }
if let title { } else if let group = peer as? TelegramGroup {
itemList.append(title) if group.hasBannedPermission(right) {
continue
} }
} }
var title: String?
switch right {
case .banSendText:
title = "text messages"
case .banSendPhotos:
title = "photos"
case .banSendVideos:
title = "videos"
case .banSendVoice:
title = "voice messages"
case .banSendInstantVideos:
title = "video messages"
case .banSendFiles:
title = "files"
case .banSendMusic:
title = "music"
case .banSendStickers:
title = "Stickers & GIFs"
default:
break
}
if let title {
itemList.append(title)
}
} }
if itemList.isEmpty { if itemList.isEmpty {

View File

@ -128,6 +128,9 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, pee
scope = [.installed] scope = [.installed]
} }
return context.engine.stickers.searchStickers(query: query.basicEmoji.0, scope: scope) return context.engine.stickers.searchStickers(query: query.basicEmoji.0, scope: scope)
|> map { items -> [FoundStickerItem] in
return items.items
}
|> castError(ChatContextQueryError.self) |> castError(ChatContextQueryError.self)
} }
|> map { stickers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in |> map { stickers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in

View File

@ -196,15 +196,15 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
} }
} }
if isMember && channel.hasBannedPermission(.banSendText) != nil && !channel.flags.contains(.isGigagroup) { if isMember && !channel.hasPermission(.sendSomething) && !channel.flags.contains(.isGigagroup) {
/*if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
return (currentPanel, nil) return (currentPanel, nil)
} else { } else {
let panel = ChatRestrictedInputPanelNode() let panel = ChatRestrictedInputPanelNode()
panel.context = context panel.context = context
panel.interfaceInteraction = interfaceInteraction panel.interfaceInteraction = interfaceInteraction
return (panel, nil) return (panel, nil)
}*/ }
} }
switch channel.info { switch channel.info {
@ -280,15 +280,15 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
break break
} }
if group.hasBannedPermission(.banSendText) { if !group.hasPermission(.sendSomething) {
/*if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
return (currentPanel, nil) return (currentPanel, nil)
} else { } else {
let panel = ChatRestrictedInputPanelNode() let panel = ChatRestrictedInputPanelNode()
panel.context = context panel.context = context
panel.interfaceInteraction = interfaceInteraction panel.interfaceInteraction = interfaceInteraction
return (panel, nil) return (panel, nil)
}*/ }
} }
} }

View File

@ -2126,9 +2126,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
mediaInputDisabled = true mediaInputDisabled = true
} else if interfaceState.hasActiveGroupCall { } else if interfaceState.hasActiveGroupCall {
mediaInputDisabled = true mediaInputDisabled = true
} else if let channel = interfaceState.renderedPeer?.peer as? TelegramChannel, channel.hasBannedPermission(.banSendMedia) != nil { } else if let channel = interfaceState.renderedPeer?.peer as? TelegramChannel, channel.hasBannedPermission(.banSendVoice) != nil, channel.hasBannedPermission(.banSendInstantVideos) != nil {
mediaInputDisabled = true mediaInputDisabled = true
} else if let group = interfaceState.renderedPeer?.peer as? TelegramGroup, group.hasBannedPermission(.banSendMedia) { } else if let group = interfaceState.renderedPeer?.peer as? TelegramGroup, group.hasBannedPermission(.banSendVoice), group.hasBannedPermission(.banSendInstantVideos) {
mediaInputDisabled = true mediaInputDisabled = true
} else { } else {
mediaInputDisabled = false mediaInputDisabled = false

View File

@ -191,7 +191,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
return ("URL", contents) return ("URL", contents)
}), textAlignment: .natural) }), textAlignment: .natural)
self.textNode.attributedText = attributedText self.textNode.attributedText = attributedText
self.textNode.maximumNumberOfLines = 2 self.textNode.maximumNumberOfLines = 10
displayUndo = false displayUndo = false
self.originalRemainingSeconds = Double(max(5, min(8, text.count / 14))) self.originalRemainingSeconds = Double(max(5, min(8, text.count / 14)))