mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
bb536aec28
@ -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,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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) }) {
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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))))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)))
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user