mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
UI improvements
This commit is contained in:
parent
f9127e3ebe
commit
263778c906
@ -154,10 +154,12 @@ public enum PagerComponentPanelHideBehavior {
|
||||
public final class PagerComponentContentIcon: Equatable {
|
||||
public let id: AnyHashable
|
||||
public let imageName: String
|
||||
public let title: String
|
||||
|
||||
public init(id: AnyHashable, imageName: String) {
|
||||
public init(id: AnyHashable, imageName: String, title: String) {
|
||||
self.id = id
|
||||
self.imageName = imageName
|
||||
self.title = title
|
||||
}
|
||||
|
||||
public static func ==(lhs: PagerComponentContentIcon, rhs: PagerComponentContentIcon) -> Bool {
|
||||
@ -170,6 +172,9 @@ public final class PagerComponentContentIcon: Equatable {
|
||||
if lhs.imageName != rhs.imageName {
|
||||
return false
|
||||
}
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -301,6 +306,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
|
||||
private struct PaneTransitionGestureState {
|
||||
var fraction: CGFloat = 0.0
|
||||
var nextIndex: Int? = nil
|
||||
}
|
||||
|
||||
private var contentClippingView: UIView
|
||||
@ -371,6 +377,15 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
}
|
||||
paneTransitionGestureState.fraction = fraction
|
||||
|
||||
let nextIndex: Int
|
||||
if fraction > 0.0 {
|
||||
nextIndex = max(0, centralIndex - 1)
|
||||
} else {
|
||||
nextIndex = min(component.contents.count - 1, centralIndex + 1)
|
||||
}
|
||||
|
||||
paneTransitionGestureState.nextIndex = nextIndex
|
||||
|
||||
self.paneTransitionGestureState = paneTransitionGestureState
|
||||
self.state?.updated(transition: .immediate)
|
||||
}
|
||||
@ -422,8 +437,26 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
}
|
||||
|
||||
public func navigateToContentId(_ id: AnyHashable) {
|
||||
guard let centralId = self.centralId, let component = self.component, let _ = component.contents.firstIndex(where: { $0.id == centralId }), let nextIndex = component.contents.firstIndex(where: { $0.id == id }) else {
|
||||
return
|
||||
}
|
||||
|
||||
var updateTopPanelExpanded = false
|
||||
if self.centralId != id {
|
||||
var paneTransitionGestureState = PaneTransitionGestureState()
|
||||
paneTransitionGestureState.fraction = 0.0
|
||||
paneTransitionGestureState.nextIndex = nextIndex
|
||||
|
||||
self.paneTransitionGestureState = paneTransitionGestureState
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
self.paneTransitionGestureState = nil
|
||||
|
||||
/*paneTransitionGestureState.fraction = 1.0
|
||||
|
||||
self.paneTransitionGestureState = paneTransitionGestureState
|
||||
self.state?.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .spring)))*/
|
||||
|
||||
self.centralId = id
|
||||
|
||||
if self.isTopPanelExpanded {
|
||||
@ -470,8 +503,8 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
}
|
||||
}
|
||||
if centralId == nil {
|
||||
centralId = component.contents.first?.id
|
||||
}
|
||||
centralId = component.contents.first?.id
|
||||
}
|
||||
}
|
||||
|
||||
if self.centralId != centralId {
|
||||
@ -494,8 +527,42 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
scrollingPanelOffsetFraction = 0.0
|
||||
}
|
||||
|
||||
var topPanelVisibility: CGFloat = 1.0
|
||||
if let centralId = centralId, let index = component.contents.firstIndex(where: { $0.id == centralId }) {
|
||||
if let paneTransitionGestureState = self.paneTransitionGestureState {
|
||||
var nextIndex: Int
|
||||
if paneTransitionGestureState.fraction > 0.0 {
|
||||
nextIndex = max(0, index - 1)
|
||||
} else {
|
||||
nextIndex = min(component.contents.count - 1, index + 1)
|
||||
}
|
||||
if let nextIndexValue = paneTransitionGestureState.nextIndex {
|
||||
nextIndex = nextIndexValue
|
||||
}
|
||||
|
||||
let nextId = component.contents[nextIndex].id
|
||||
|
||||
var centralPanelFraction: CGFloat = 1.0
|
||||
if !component.contentTopPanels.contains(where: { $0.id == centralId }) {
|
||||
centralPanelFraction = 0.0
|
||||
}
|
||||
var nextPanelFraction: CGFloat = 1.0
|
||||
if !component.contentTopPanels.contains(where: { $0.id == nextId }) {
|
||||
nextPanelFraction = 0.0
|
||||
}
|
||||
|
||||
topPanelVisibility = centralPanelFraction * (1.0 - abs(paneTransitionGestureState.fraction)) + nextPanelFraction * abs(paneTransitionGestureState.fraction)
|
||||
} else {
|
||||
if !component.contentTopPanels.contains(where: { $0.id == centralId }) {
|
||||
topPanelVisibility = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var topPanelHeight: CGFloat = 0.0
|
||||
if let topPanel = component.topPanel {
|
||||
let effectiveTopPanelOffsetFraction = scrollingPanelOffsetFraction
|
||||
|
||||
let topPanelView: ComponentHostView<PagerComponentPanelEnvironment<TopPanelEnvironment>>
|
||||
var topPanelTransition = panelStateTransition
|
||||
if let current = self.topPanelView {
|
||||
@ -511,6 +578,11 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
topPanelSuperview.addSubview(topPanelView)
|
||||
}
|
||||
|
||||
var effectivePanelActiveContentId = centralId
|
||||
if let centralId = centralId, !component.contentTopPanels.contains(where: { $0.id == centralId }) {
|
||||
effectivePanelActiveContentId = component.contentTopPanels.first?.id
|
||||
}
|
||||
|
||||
let topPanelSize = topPanelView.update(
|
||||
transition: topPanelTransition,
|
||||
component: topPanel,
|
||||
@ -522,7 +594,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
contentIcons: [],
|
||||
contentAccessoryLeftButtons: [],
|
||||
contentAccessoryRightButtons: [],
|
||||
activeContentId: centralId,
|
||||
activeContentId: effectivePanelActiveContentId,
|
||||
navigateToContentId: navigateToContentId,
|
||||
visibilityFractionUpdated: self.topPanelVisibilityFractionUpdated,
|
||||
isExpandedUpdated: { [weak self] isExpanded, transition in
|
||||
@ -538,9 +610,11 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
|
||||
self.topPanelHeight = topPanelSize.height
|
||||
|
||||
var topPanelOffset = topPanelSize.height * scrollingPanelOffsetFraction
|
||||
var topPanelOffset = topPanelSize.height * effectiveTopPanelOffsetFraction
|
||||
|
||||
var topPanelVisibilityFraction: CGFloat = 1.0 - scrollingPanelOffsetFraction
|
||||
topPanelOffset = min(topPanelSize.height, topPanelOffset + topPanelSize.height * (1.0 - topPanelVisibility))
|
||||
|
||||
var topPanelVisibilityFraction: CGFloat = 1.0 - effectiveTopPanelOffsetFraction
|
||||
switch component.panelHideBehavior {
|
||||
case .hide:
|
||||
topPanelVisibilityFraction = 0.0
|
||||
@ -549,6 +623,7 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
case .hideOnScroll:
|
||||
break
|
||||
}
|
||||
topPanelVisibilityFraction *= topPanelVisibility
|
||||
|
||||
self.topPanelVisibilityFractionUpdated.invoke((topPanelVisibilityFraction, topPanelTransition))
|
||||
|
||||
@ -645,6 +720,8 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
self.bottomPanelHeight = 0.0
|
||||
}
|
||||
|
||||
contentInsets.top *= topPanelVisibility
|
||||
|
||||
let effectiveTopPanelHeight: CGFloat
|
||||
switch component.panelHideBehavior {
|
||||
case .hide:
|
||||
@ -699,14 +776,16 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
||||
var checkingContentFrame = CGRect(origin: CGPoint(x: contentSize.width * CGFloat(indexOffset), y: 0.0), size: contentSize)
|
||||
var contentFrame = CGRect(origin: CGPoint(x: contentSize.width * CGFloat(clippedIndexOffset), y: 0.0), size: contentSize)
|
||||
|
||||
var isInBounds = CGRect(origin: CGPoint(), size: availableSize).intersects(checkingContentFrame)
|
||||
if let paneTransitionGestureState = self.paneTransitionGestureState {
|
||||
checkingContentFrame.origin.x += paneTransitionGestureState.fraction * availableSize.width
|
||||
contentFrame.origin.x += paneTransitionGestureState.fraction * availableSize.width
|
||||
if let nextIndex = paneTransitionGestureState.nextIndex, nextIndex == index {
|
||||
isInBounds = true
|
||||
}
|
||||
}
|
||||
let content = component.contents[index]
|
||||
|
||||
let isInBounds = CGRect(origin: CGPoint(), size: availableSize).intersects(checkingContentFrame)
|
||||
|
||||
var isPartOfTransition = false
|
||||
if case .none = transition.animation {
|
||||
} else if self.contentViews[content.id] != nil {
|
||||
|
@ -732,7 +732,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
|
||||
reactionContextNode.updateLayout(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: 0.0, right: layout.safeInsets.right), anchorRect: reactionAnchorRect, isCoveredByInput: isCoveredByInput, isAnimatingOut: isAnimatingOut, transition: reactionContextNodeTransition)
|
||||
|
||||
self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - 46.0
|
||||
self.proposedReactionsPositionLock = contentRect.minY - 18.0 - reactionContextNode.contentHeight - (46.0 + 54.0 - 4.0)
|
||||
} else {
|
||||
self.proposedReactionsPositionLock = nil
|
||||
}
|
||||
|
@ -906,7 +906,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
expandItemSize = 30.0
|
||||
expandTintOffset = 0.0
|
||||
}
|
||||
let baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0) + (self.isExpanded ? (46.0) : 0.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance))
|
||||
let baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0) + (self.isExpanded ? (46.0 + 54.0 - 4.0) : 0.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance))
|
||||
|
||||
transition.updateFrame(view: expandItemView, frame: baseNextFrame)
|
||||
transition.updateFrame(view: expandItemView.tintView, frame: baseNextFrame.offsetBy(dx: 0.0, dy: expandTintOffset))
|
||||
@ -1007,7 +1007,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
visibleItemCount: itemCount
|
||||
)
|
||||
|
||||
var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.isExpanded ? (46.0) : 0.0), size: actualBackgroundFrame.size)
|
||||
var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.isExpanded ? (46.0 + 54.0 - 4.0) : 0.0), size: actualBackgroundFrame.size)
|
||||
scrollFrame.origin.y += floorToScreenPixels(self.extensionDistance / 2.0)
|
||||
|
||||
transition.updateFrame(node: self.contentContainer, frame: visualBackgroundFrame, beginWithCurrentState: true)
|
||||
@ -1107,7 +1107,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
if let mirrorContentClippingView = emojiView.mirrorContentClippingView {
|
||||
mirrorContentClippingView.clipsToBounds = false
|
||||
Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: 46.0), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in
|
||||
Transition(transition).animateBoundsOrigin(view: mirrorContentClippingView, from: CGPoint(x: 0.0, y: 46.0 + 54.0 - 4.0), to: CGPoint(), additive: true, completion: { [weak mirrorContentClippingView] _ in
|
||||
mirrorContentClippingView?.clipsToBounds = true
|
||||
})
|
||||
}
|
||||
@ -1138,7 +1138,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
componentTransition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height)))
|
||||
|
||||
if animateIn {
|
||||
transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -(46.0) + floorToScreenPixels(self.animateFromExtensionDistance / 2.0)))
|
||||
transition.animatePositionAdditive(layer: componentView.layer, offset: CGPoint(x: 0.0, y: -(46.0 + 54.0 - 4.0) + floorToScreenPixels(self.animateFromExtensionDistance / 2.0)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,13 +68,13 @@ public final class EntityKeyboardGifContent: Equatable {
|
||||
|
||||
public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
public struct InputData: Equatable {
|
||||
public var emoji: EmojiPagerContentComponent
|
||||
public var emoji: EmojiPagerContentComponent?
|
||||
public var stickers: EmojiPagerContentComponent?
|
||||
public var gifs: EntityKeyboardGifContent?
|
||||
public var availableGifSearchEmojies: [EntityKeyboardComponent.GifSearchEmoji]
|
||||
|
||||
public init(
|
||||
emoji: EmojiPagerContentComponent,
|
||||
emoji: EmojiPagerContentComponent?,
|
||||
stickers: EmojiPagerContentComponent?,
|
||||
gifs: EntityKeyboardGifContent?,
|
||||
availableGifSearchEmojies: [EntityKeyboardComponent.GifSearchEmoji]
|
||||
@ -159,6 +159,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
loadMore: { _ in
|
||||
},
|
||||
openSearch: {
|
||||
},
|
||||
updateSearchQuery: { _ in
|
||||
}
|
||||
)
|
||||
|
||||
@ -173,6 +175,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
isLoading: false,
|
||||
loadMoreToken: nil,
|
||||
displaySearchWithPlaceholder: nil,
|
||||
searchCategories: nil,
|
||||
searchInitiallyHidden: true
|
||||
)
|
||||
))
|
||||
@ -243,6 +246,9 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
private let emojiSearchDisposable = MetaDisposable()
|
||||
private let emojiSearchResult = Promise<(groups: [EmojiPagerContentComponent.ItemGroup], id: AnyHashable)?>(nil)
|
||||
|
||||
private let stickerSearchDisposable = MetaDisposable()
|
||||
private let stickerSearchResult = Promise<(groups: [EmojiPagerContentComponent.ItemGroup], id: AnyHashable)?>(nil)
|
||||
|
||||
private let controllerInteraction: ChatControllerInteraction?
|
||||
|
||||
private var inputNodeInteraction: ChatMediaInputNodeInteraction?
|
||||
@ -320,12 +326,17 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
return !savedGifs.isEmpty
|
||||
}
|
||||
|
||||
let searchCategories: Signal<EmojiSearchCategories?, NoError> = context.engine.stickers.emojiSearchCategories(kind: .emoji)
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let gifItems: Signal<EntityKeyboardGifContent, NoError>
|
||||
switch subject {
|
||||
case .recent:
|
||||
gifItems = context.engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs))
|
||||
|> map { savedGifs -> EntityKeyboardGifContent in
|
||||
gifItems = combineLatest(
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs)),
|
||||
searchCategories
|
||||
)
|
||||
|> map { savedGifs, searchCategories -> EntityKeyboardGifContent in
|
||||
var items: [GifPagerContentComponent.Item] = []
|
||||
for gifItem in savedGifs {
|
||||
items.append(GifPagerContentComponent.Item(
|
||||
@ -342,14 +353,15 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
items: items,
|
||||
isLoading: false,
|
||||
loadMoreToken: nil,
|
||||
displaySearchWithPlaceholder: presentationData.strings.GifSearch_SearchGifPlaceholder,
|
||||
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true
|
||||
)
|
||||
)
|
||||
}
|
||||
case .trending:
|
||||
gifItems = combineLatest(hasRecentGifs, trendingGifs)
|
||||
|> map { hasRecentGifs, trendingGifs -> EntityKeyboardGifContent in
|
||||
gifItems = combineLatest(hasRecentGifs, trendingGifs, searchCategories)
|
||||
|> map { hasRecentGifs, trendingGifs, searchCategories -> EntityKeyboardGifContent in
|
||||
var items: [GifPagerContentComponent.Item] = []
|
||||
|
||||
var isLoading = false
|
||||
@ -373,14 +385,19 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
items: items,
|
||||
isLoading: isLoading,
|
||||
loadMoreToken: nil,
|
||||
displaySearchWithPlaceholder: nil,
|
||||
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true
|
||||
)
|
||||
)
|
||||
}
|
||||
case let .emojiSearch(query):
|
||||
gifItems = combineLatest(hasRecentGifs, paneGifSearchForQuery(context: context, query: query, offset: nil, incompleteResults: true, staleCachedResults: true, delayRequest: false, updateActivity: nil))
|
||||
|> map { hasRecentGifs, result -> EntityKeyboardGifContent in
|
||||
gifItems = combineLatest(
|
||||
hasRecentGifs,
|
||||
paneGifSearchForQuery(context: context, query: query, offset: nil, incompleteResults: true, staleCachedResults: true, delayRequest: false, updateActivity: nil),
|
||||
searchCategories
|
||||
)
|
||||
|> map { hasRecentGifs, result, searchCategories -> EntityKeyboardGifContent in
|
||||
var items: [GifPagerContentComponent.Item] = []
|
||||
|
||||
var loadMoreToken: String?
|
||||
@ -406,7 +423,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
items: items,
|
||||
isLoading: isLoading,
|
||||
loadMoreToken: loadMoreToken,
|
||||
displaySearchWithPlaceholder: nil,
|
||||
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true
|
||||
)
|
||||
)
|
||||
@ -448,9 +466,12 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
return !savedGifs.isEmpty
|
||||
}
|
||||
|
||||
let searchCategories: Signal<EmojiSearchCategories?, NoError> = context.engine.stickers.emojiSearchCategories(kind: .emoji)
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let gifItems: Signal<EntityKeyboardGifContent, NoError>
|
||||
gifItems = combineLatest(hasRecentGifs, paneGifSearchForQuery(context: context, query: query, offset: token, incompleteResults: true, staleCachedResults: true, delayRequest: false, updateActivity: nil))
|
||||
|> map { hasRecentGifs, result -> EntityKeyboardGifContent in
|
||||
gifItems = combineLatest(hasRecentGifs, paneGifSearchForQuery(context: context, query: query, offset: token, incompleteResults: true, staleCachedResults: true, delayRequest: false, updateActivity: nil), searchCategories)
|
||||
|> map { hasRecentGifs, result, searchCategories -> EntityKeyboardGifContent in
|
||||
var items: [GifPagerContentComponent.Item] = []
|
||||
var existingIds = Set<MediaId>()
|
||||
for item in componentValue.component.items {
|
||||
@ -487,7 +508,8 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
items: items,
|
||||
isLoading: isLoading,
|
||||
loadMoreToken: loadMoreToken,
|
||||
displaySearchWithPlaceholder: nil,
|
||||
displaySearchWithPlaceholder: presentationData.strings.Common_Search,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true
|
||||
)
|
||||
)
|
||||
@ -1002,7 +1024,6 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
}
|
||||
|
||||
strongSelf.emojiSearchDisposable.set((resultSignal
|
||||
|> delay(0.15, queue: .mainQueue())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1214,7 +1235,66 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
},
|
||||
requestUpdate: { _ in
|
||||
},
|
||||
updateSearchQuery: { _ in
|
||||
updateSearchQuery: { [weak self] query in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch query {
|
||||
case .none:
|
||||
strongSelf.stickerSearchDisposable.set(nil)
|
||||
strongSelf.stickerSearchResult.set(.single(nil))
|
||||
case .text:
|
||||
strongSelf.stickerSearchDisposable.set(nil)
|
||||
strongSelf.stickerSearchResult.set(.single(nil))
|
||||
case let .category(value):
|
||||
let resultSignal = strongSelf.context.engine.stickers.searchStickers(query: value, scope: [.installed, .remote])
|
||||
|> mapToSignal { files -> Signal<[EmojiPagerContentComponent.ItemGroup], NoError> in
|
||||
var items: [EmojiPagerContentComponent.Item] = []
|
||||
|
||||
var existingIds = Set<MediaId>()
|
||||
for item in files {
|
||||
let itemFile = item.file
|
||||
if existingIds.contains(itemFile.fileId) {
|
||||
continue
|
||||
}
|
||||
existingIds.insert(itemFile.fileId)
|
||||
let animationData = EntityKeyboardAnimationData(file: itemFile)
|
||||
let item = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
content: .animation(animationData),
|
||||
itemFile: itemFile, subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: animationData.isTemplate ? .primary : .none
|
||||
)
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
return .single([EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
groupId: "search",
|
||||
title: nil,
|
||||
subtitle: nil,
|
||||
actionButtonTitle: nil,
|
||||
isFeatured: false,
|
||||
isPremiumLocked: false,
|
||||
isEmbedded: false,
|
||||
hasClear: false,
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
items: items
|
||||
)])
|
||||
}
|
||||
|
||||
strongSelf.stickerSearchDisposable.set((resultSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.stickerSearchResult.set(.single((result, AnyHashable(value))))
|
||||
}))
|
||||
}
|
||||
},
|
||||
updateScrollingToItemGroup: {
|
||||
},
|
||||
@ -1230,9 +1310,10 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
self.inputDataDisposable = (combineLatest(queue: .mainQueue(),
|
||||
updatedInputData,
|
||||
self.gifComponent.get(),
|
||||
self.emojiSearchResult.get()
|
||||
self.emojiSearchResult.get(),
|
||||
self.stickerSearchResult.get()
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] inputData, gifs, emojiSearchResult in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] inputData, gifs, emojiSearchResult, stickerSearchResult in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1249,7 +1330,23 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
iconFile: nil
|
||||
)
|
||||
}
|
||||
inputData.emoji = inputData.emoji.withUpdatedItemGroups(panelItemGroups: inputData.emoji.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
if let emoji = inputData.emoji {
|
||||
inputData.emoji = emoji.withUpdatedItemGroups(panelItemGroups: emoji.panelItemGroups, contentItemGroups: emojiSearchResult.groups, itemContentUniqueId: emojiSearchResult.id, emptySearchResults: emptySearchResults)
|
||||
}
|
||||
}
|
||||
|
||||
if let stickerSearchResult = stickerSearchResult {
|
||||
var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
||||
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty }) {
|
||||
//TODO:localize
|
||||
stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults(
|
||||
text: "No stickers found",
|
||||
iconFile: nil
|
||||
)
|
||||
}
|
||||
if let stickers = inputData.stickers {
|
||||
inputData.stickers = stickers.withUpdatedItemGroups(panelItemGroups: stickers.panelItemGroups, contentItemGroups: stickerSearchResult.groups, itemContentUniqueId: stickerSearchResult.id, emptySearchResults: stickerSearchResults)
|
||||
}
|
||||
}
|
||||
|
||||
var transition: Transition = .immediate
|
||||
@ -1338,6 +1435,16 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
if let strongSelf = self, let pagerView = strongSelf.entityKeyboardView.componentView as? EntityKeyboardComponent.View {
|
||||
pagerView.openSearch()
|
||||
}
|
||||
},
|
||||
updateSearchQuery: { [weak self] query in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let query {
|
||||
self.gifMode = .emojiSearch(query)
|
||||
} else {
|
||||
self.gifMode = .recent
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@ -1377,6 +1484,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
self.inputDataDisposable?.dispose()
|
||||
self.hasRecentGifsDisposable?.dispose()
|
||||
self.emojiSearchDisposable.dispose()
|
||||
self.stickerSearchDisposable.dispose()
|
||||
}
|
||||
|
||||
private func reloadGifContext() {
|
||||
@ -1439,27 +1547,38 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
mappedTransition = mappedTransition.withUserData(EntityKeyboardComponent.MarkInputCollapsed())
|
||||
}
|
||||
|
||||
var emojiContent: EmojiPagerContentComponent? = self.currentInputData.emoji
|
||||
var stickerContent: EmojiPagerContentComponent? = self.currentInputData.stickers
|
||||
var gifContent: EntityKeyboardGifContent? = self.currentInputData.gifs
|
||||
|
||||
var stickersEnabled = true
|
||||
var emojiEnabled = true
|
||||
if let peer = interfaceState.renderedPeer?.peer as? TelegramChannel {
|
||||
if peer.hasBannedPermission(.banSendStickers) != nil {
|
||||
stickersEnabled = false
|
||||
}
|
||||
if peer.hasBannedPermission(.banSendText) != nil {
|
||||
emojiEnabled = false
|
||||
}
|
||||
} else if let peer = interfaceState.renderedPeer?.peer as? TelegramGroup {
|
||||
if peer.hasBannedPermission(.banSendStickers) {
|
||||
stickersEnabled = false
|
||||
}
|
||||
if peer.hasBannedPermission(.banSendText) {
|
||||
emojiEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
if !stickersEnabled || interfaceState.interfaceState.editMessage != nil {
|
||||
stickerContent = nil
|
||||
gifContent = nil
|
||||
}
|
||||
if !emojiEnabled && interfaceState.interfaceState.editMessage == nil {
|
||||
emojiContent = nil
|
||||
}
|
||||
|
||||
stickerContent?.inputInteractionHolder.inputInteraction = self.stickerInputInteraction
|
||||
self.currentInputData.emoji.inputInteractionHolder.inputInteraction = self.emojiInputInteraction
|
||||
self.currentInputData.emoji?.inputInteractionHolder.inputInteraction = self.emojiInputInteraction
|
||||
|
||||
let startTime = CFAbsoluteTimeGetCurrent()
|
||||
|
||||
@ -1471,7 +1590,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
isContentInFocus: isVisible,
|
||||
containerInsets: UIEdgeInsets(top: self.isEmojiSearchActive ? -34.0 : 0.0, left: leftInset, bottom: bottomInset, right: rightInset),
|
||||
topPanelInsets: UIEdgeInsets(),
|
||||
emojiContent: self.currentInputData.emoji,
|
||||
emojiContent: emojiContent,
|
||||
stickerContent: stickerContent,
|
||||
maskContent: nil,
|
||||
gifContent: gifContent?.component,
|
||||
@ -1639,7 +1758,9 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
|
||||
private func processInputData(inputData: InputData) -> InputData {
|
||||
return InputData(
|
||||
emoji: inputData.emoji.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: inputData.emoji.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: inputData.emoji.contentItemGroups), itemContentUniqueId: inputData.emoji.itemContentUniqueId, emptySearchResults: inputData.emoji.emptySearchResults),
|
||||
emoji: inputData.emoji.flatMap { emoji in
|
||||
return emoji.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .emoji, itemGroups: emoji.contentItemGroups), itemContentUniqueId: emoji.itemContentUniqueId, emptySearchResults: emoji.emptySearchResults)
|
||||
},
|
||||
stickers: inputData.stickers.flatMap { stickers in
|
||||
return stickers.withUpdatedItemGroups(panelItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.panelItemGroups), contentItemGroups: self.processStableItemGroupList(category: .stickers, itemGroups: stickers.contentItemGroups), itemContentUniqueId: nil, emptySearchResults: nil)
|
||||
},
|
||||
|
@ -1569,7 +1569,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
return PassthroughLayer.self
|
||||
}
|
||||
|
||||
private let activated: () -> Void
|
||||
private let activated: (Bool) -> Void
|
||||
private let deactivated: (Bool) -> Void
|
||||
private let updateQuery: (EmojiPagerContentComponent.SearchQuery?) -> Void
|
||||
|
||||
@ -1606,7 +1606,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
return self.textField != nil
|
||||
}
|
||||
|
||||
init(activated: @escaping () -> Void, deactivated: @escaping (Bool) -> Void, updateQuery: @escaping (EmojiPagerContentComponent.SearchQuery?) -> Void) {
|
||||
init(activated: @escaping (Bool) -> Void, deactivated: @escaping (Bool) -> Void, updateQuery: @escaping (EmojiPagerContentComponent.SearchQuery?) -> Void) {
|
||||
self.activated = activated
|
||||
self.deactivated = deactivated
|
||||
self.updateQuery = updateQuery
|
||||
@ -1735,7 +1735,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
placeholderContentView.clearSelection(dispatchEvent: false)
|
||||
}
|
||||
|
||||
self.activated()
|
||||
self.activated(true)
|
||||
|
||||
self.textField?.becomeFirstResponder()
|
||||
}
|
||||
@ -1965,7 +1965,7 @@ public final class EmojiSearchHeaderView: UIView, UITextFieldDelegate {
|
||||
|
||||
if let term {
|
||||
self.updateQuery(.category(value: term))
|
||||
self.activated()
|
||||
self.activated(false)
|
||||
} else {
|
||||
self.deactivated(self.textField?.isFirstResponder ?? false)
|
||||
self.updateQuery(nil)
|
||||
@ -6175,7 +6175,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
let scrollSize = CGSize(width: availableSize.width, height: availableSize.height)
|
||||
transition.setPosition(view: self.scrollView, position: CGPoint(x: 0.0, y: scrollOriginY))
|
||||
|
||||
let clippingTopInset: CGFloat = itemLayout.searchInsets.top + itemLayout.searchHeight + 2.0
|
||||
let clippingTopInset: CGFloat = itemLayout.searchInsets.top + itemLayout.searchHeight - 1.0
|
||||
|
||||
transition.setFrame(view: self.scrollViewClippingView, frame: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize))
|
||||
transition.setBounds(view: self.scrollViewClippingView, bounds: CGRect(origin: CGPoint(x: 0.0, y: self.isSearchActivated ? clippingTopInset : 0.0), size: availableSize))
|
||||
@ -6364,12 +6364,12 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
visibleSearchHeader = EmojiSearchHeaderView(activated: { [weak self] in
|
||||
visibleSearchHeader = EmojiSearchHeaderView(activated: { [weak self] isTextInput in
|
||||
guard let strongSelf = self, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
|
||||
return
|
||||
}
|
||||
|
||||
if let component = strongSelf.component, component.searchIsPlaceholderOnly {
|
||||
if let component = strongSelf.component, component.searchIsPlaceholderOnly, isTextInput {
|
||||
component.inputInteractionHolder.inputInteraction?.openSearch()
|
||||
} else {
|
||||
strongSelf.isSearchActivated = true
|
||||
@ -7435,15 +7435,18 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
|
||||
let searchCategories: Signal<EmojiSearchCategories?, NoError> = context.engine.stickers.emojiSearchCategories(kind: .emoji)
|
||||
|
||||
return combineLatest(
|
||||
context.account.postbox.itemCollectionsView(orderedItemListCollectionIds: stickerOrderedItemListCollectionIds, namespaces: stickerNamespaces, aroundIndex: nil, count: 10000000),
|
||||
hasPremium(context: context, chatPeerId: chatPeerId, premiumIfSavedMessages: false),
|
||||
hasTrending ? context.account.viewTracker.featuredStickerPacks() : .single([]),
|
||||
context.engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.featuredStickersConfiguration, id: ValueBoxKey(length: 0))),
|
||||
ApplicationSpecificNotice.dismissedTrendingStickerPacks(accountManager: context.sharedContext.accountManager),
|
||||
peerSpecificPack
|
||||
peerSpecificPack,
|
||||
searchCategories
|
||||
)
|
||||
|> map { view, hasPremium, featuredStickerPacks, featuredStickersConfiguration, dismissedTrendingStickerPacks, peerSpecificPack -> EmojiPagerContentComponent in
|
||||
|> map { view, hasPremium, featuredStickerPacks, featuredStickersConfiguration, dismissedTrendingStickerPacks, peerSpecificPack, searchCategories -> EmojiPagerContentComponent in
|
||||
let actuallyHasPremium = hasPremium
|
||||
let hasPremium = forceHasPremium || hasPremium
|
||||
struct ItemGroup {
|
||||
@ -7880,7 +7883,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemContentUniqueId: nil,
|
||||
warpContentsOnEdges: false,
|
||||
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
|
||||
searchCategories: nil,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true,
|
||||
searchIsPlaceholderOnly: searchIsPlaceholderOnly,
|
||||
emptySearchResults: nil,
|
||||
|
@ -108,6 +108,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
let contentSize: CGSize
|
||||
let leftInset: CGFloat
|
||||
let rightInset: CGFloat
|
||||
let itemStartX: CGFloat
|
||||
|
||||
let textSpacing: CGFloat
|
||||
let textFrame: CGRect
|
||||
@ -123,11 +124,13 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
|
||||
self.textFrame = CGRect(origin: CGPoint(x: self.leftInset, y: floor((containerSize.height - textSize.height) * 0.5)), size: textSize)
|
||||
|
||||
self.contentSize = CGSize(width: self.leftInset + textSize.width + self.textSpacing + self.itemSize.width * CGFloat(self.itemCount) + self.itemSpacing * CGFloat(max(0, self.itemCount - 1)) + self.rightInset, height: containerSize.height)
|
||||
self.itemStartX = max(self.textFrame.maxX + self.textSpacing, self.leftInset + floor(((containerSize.width - self.leftInset - self.rightInset) / 2.0) - self.itemSize.width))
|
||||
|
||||
self.contentSize = CGSize(width: self.itemStartX + self.itemSize.width * CGFloat(self.itemCount) + self.itemSpacing * CGFloat(max(0, self.itemCount - 1)) + self.rightInset, height: containerSize.height)
|
||||
}
|
||||
|
||||
func visibleItems(for rect: CGRect) -> Range<Int>? {
|
||||
let baseItemX: CGFloat = self.textFrame.maxX + self.textSpacing
|
||||
let baseItemX: CGFloat = self.itemStartX
|
||||
let offsetRect = rect.offsetBy(dx: -baseItemX, dy: 0.0)
|
||||
var minVisibleIndex = Int(floor((offsetRect.minX - self.itemSpacing) / (self.itemSize.width + self.itemSpacing)))
|
||||
minVisibleIndex = max(0, minVisibleIndex)
|
||||
@ -142,7 +145,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
}
|
||||
|
||||
func frame(at index: Int) -> CGRect {
|
||||
return CGRect(origin: CGPoint(x: self.textFrame.maxX + self.textSpacing + CGFloat(index) * (self.itemSize.width + self.itemSpacing), y: floor((self.containerSize.height - self.itemSize.height) * 0.5)), size: self.itemSize)
|
||||
return CGRect(origin: CGPoint(x: self.itemStartX + CGFloat(index) * (self.itemSize.width + self.itemSpacing), y: floor((self.containerSize.height - self.itemSize.height) * 0.5)), size: self.itemSize)
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,8 +187,11 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
private let scrollView: ContentScrollView
|
||||
private let tintScrollView: UIView
|
||||
|
||||
private let tintTextView = ComponentView<Empty>()
|
||||
private let textView = ComponentView<Empty>()
|
||||
private let textContainerView: UIView
|
||||
|
||||
private let tintTextView = ComponentView<Empty>()
|
||||
private let tintTextContainerView: UIView
|
||||
|
||||
private var visibleItemViews: [AnyHashable: ItemView] = [:]
|
||||
private let selectedItemBackground: SimpleLayer
|
||||
@ -209,6 +215,11 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
self.tintScrollView.clipsToBounds = true
|
||||
self.scrollView = ContentScrollView(mirrorView: self.tintScrollView)
|
||||
|
||||
self.textContainerView = UIView()
|
||||
self.textContainerView.isUserInteractionEnabled = false
|
||||
self.tintTextContainerView = UIView()
|
||||
self.tintTextContainerView.isUserInteractionEnabled = false
|
||||
|
||||
self.roundMaskView = RoundMaskView()
|
||||
self.tintRoundMaskView = RoundMaskView()
|
||||
|
||||
@ -231,8 +242,10 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
self.scrollView.scrollsToTop = false
|
||||
|
||||
self.addSubview(self.scrollView)
|
||||
self.addSubview(self.textContainerView)
|
||||
|
||||
self.tintContainerView.addSubview(self.tintScrollView)
|
||||
self.tintContainerView.addSubview(self.tintTextContainerView)
|
||||
|
||||
self.mask = self.roundMaskView
|
||||
self.tintContainerView.mask = self.tintRoundMaskView
|
||||
@ -253,7 +266,7 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
return
|
||||
}
|
||||
let location = recognizer.location(in: self.scrollView)
|
||||
if location.x <= itemLayout.textFrame.maxX + itemLayout.textSpacing {
|
||||
if (component.categories?.groups ?? []).isEmpty || location.x <= itemLayout.itemStartX - itemLayout.textSpacing {
|
||||
component.activateTextInput()
|
||||
} else {
|
||||
for (id, itemView) in self.visibleItemViews {
|
||||
@ -265,8 +278,10 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
}
|
||||
self.state?.updated(transition: .immediate)
|
||||
|
||||
if let categories = component.categories, let group = categories.groups.first(where: { $0.id == itemId }) {
|
||||
if let _ = self.selectedItem, let categories = component.categories, let group = categories.groups.first(where: { $0.id == itemId }) {
|
||||
component.searchTermUpdated(group.identifiers.joined(separator: ""))
|
||||
} else {
|
||||
component.searchTermUpdated(nil)
|
||||
}
|
||||
|
||||
break
|
||||
@ -418,6 +433,15 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
self.selectedItemBackground.isHidden = true
|
||||
self.selectedItemTintBackground.isHidden = true
|
||||
}
|
||||
|
||||
let scrollBounds = self.scrollView.bounds
|
||||
let textOffset = max(0.0, scrollBounds.minX - (itemLayout.itemStartX - itemLayout.textFrame.maxX - itemLayout.textSpacing))
|
||||
|
||||
transition.setPosition(view: self.textContainerView, position: self.scrollView.center)
|
||||
transition.setBounds(view: self.textContainerView, bounds: CGRect(origin: CGPoint(x: textOffset, y: 0.0), size: scrollBounds.size))
|
||||
|
||||
transition.setPosition(view: self.tintTextContainerView, position: self.scrollView.center)
|
||||
transition.setBounds(view: self.tintTextContainerView, bounds: CGRect(origin: CGPoint(x: textOffset, y: 0.0), size: scrollBounds.size))
|
||||
}
|
||||
|
||||
func update(component: EmojiSearchSearchBarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
@ -450,13 +474,13 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
|
||||
if let textComponentView = self.textView.view {
|
||||
if textComponentView.superview == nil {
|
||||
self.scrollView.addSubview(textComponentView)
|
||||
self.textContainerView.addSubview(textComponentView)
|
||||
}
|
||||
transition.setFrame(view: textComponentView, frame: itemLayout.textFrame)
|
||||
}
|
||||
if let tintTextComponentView = self.tintTextView.view {
|
||||
if tintTextComponentView.superview == nil {
|
||||
self.tintScrollView.addSubview(tintTextComponentView)
|
||||
self.tintTextContainerView.addSubview(tintTextComponentView)
|
||||
}
|
||||
transition.setFrame(view: tintTextComponentView, frame: itemLayout.textFrame)
|
||||
}
|
||||
@ -465,6 +489,9 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
if self.scrollView.bounds.size != availableSize {
|
||||
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
}
|
||||
if case .active = component.textInputState {
|
||||
transition.setBounds(view: self.scrollView, bounds: CGRect(origin: CGPoint(), size: availableSize))
|
||||
}
|
||||
if self.scrollView.contentSize != itemLayout.contentSize {
|
||||
self.scrollView.contentSize = itemLayout.contentSize
|
||||
}
|
||||
@ -483,6 +510,10 @@ final class EmojiSearchSearchBarComponent: Component {
|
||||
self.isUserInteractionEnabled = false
|
||||
self.textView.view?.isHidden = hasText
|
||||
self.tintTextView.view?.isHidden = hasText
|
||||
|
||||
/*if self.scrollView.contentOffset.x != 0.0 {
|
||||
self.scrollView.setContentOffset(CGPoint(), animated: true)
|
||||
}*/
|
||||
case .inactive:
|
||||
self.isUserInteractionEnabled = true
|
||||
self.textView.view?.isHidden = false
|
||||
|
@ -368,7 +368,8 @@ public final class EntityKeyboardComponent: Component {
|
||||
strongSelf.reorderPacks(category: .masks, items: items)
|
||||
}
|
||||
))))
|
||||
contentIcons.append(PagerComponentContentIcon(id: "masks", imageName: "Chat/Input/Media/EntityInputMasksIcon"))
|
||||
//TODO:localize
|
||||
contentIcons.append(PagerComponentContentIcon(id: "masks", imageName: "Chat/Input/Media/EntityInputMasksIcon", title: "Masks"))
|
||||
if let _ = component.maskContent?.inputInteractionHolder.inputInteraction?.openStickerSettings {
|
||||
contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "masks", component: AnyComponent(Button(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
@ -385,7 +386,7 @@ public final class EntityKeyboardComponent: Component {
|
||||
|
||||
if let gifContent = component.gifContent {
|
||||
contents.append(AnyComponentWithIdentity(id: "gifs", component: AnyComponent(gifContent)))
|
||||
var topGifItems: [EntityKeyboardTopPanelComponent.Item] = []
|
||||
/*var topGifItems: [EntityKeyboardTopPanelComponent.Item] = []
|
||||
if component.hasRecentGifs {
|
||||
topGifItems.append(EntityKeyboardTopPanelComponent.Item(
|
||||
id: "recent",
|
||||
@ -453,8 +454,9 @@ public final class EntityKeyboardComponent: Component {
|
||||
activeContentItemIdUpdated: gifsContentItemIdUpdated,
|
||||
reorderItems: { _ in
|
||||
}
|
||||
))))
|
||||
contentIcons.append(PagerComponentContentIcon(id: "gifs", imageName: "Chat/Input/Media/EntityInputGifsIcon"))
|
||||
))))*/
|
||||
//TODO:localize
|
||||
contentIcons.append(PagerComponentContentIcon(id: "gifs", imageName: "Chat/Input/Media/EntityInputGifsIcon", title: "GIFs"))
|
||||
}
|
||||
|
||||
if let stickerContent = component.stickerContent {
|
||||
@ -560,7 +562,8 @@ public final class EntityKeyboardComponent: Component {
|
||||
strongSelf.reorderPacks(category: .stickers, items: items)
|
||||
}
|
||||
))))
|
||||
contentIcons.append(PagerComponentContentIcon(id: "stickers", imageName: "Chat/Input/Media/EntityInputStickersIcon"))
|
||||
//TODO:localize
|
||||
contentIcons.append(PagerComponentContentIcon(id: "stickers", imageName: "Chat/Input/Media/EntityInputStickersIcon", title: "Stickers"))
|
||||
if let _ = component.stickerContent?.inputInteractionHolder.inputInteraction?.openStickerSettings {
|
||||
contentAccessoryRightButtons.append(AnyComponentWithIdentity(id: "stickers", component: AnyComponent(Button(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
@ -659,7 +662,8 @@ public final class EntityKeyboardComponent: Component {
|
||||
strongSelf.reorderPacks(category: .emoji, items: items)
|
||||
}
|
||||
))))
|
||||
contentIcons.append(PagerComponentContentIcon(id: "emoji", imageName: "Chat/Input/Media/EntityInputEmojiIcon"))
|
||||
//TODO:localize
|
||||
contentIcons.append(PagerComponentContentIcon(id: "emoji", imageName: "Chat/Input/Media/EntityInputEmojiIcon", title: "Emoji"))
|
||||
if let _ = deleteBackwards {
|
||||
contentAccessoryLeftButtons.append(AnyComponentWithIdentity(id: "emoji", component: AnyComponent(Button(
|
||||
content: AnyComponent(BundleIconComponent(
|
||||
|
@ -10,25 +10,25 @@ import ComponentDisplayAdapters
|
||||
import BundleIconComponent
|
||||
|
||||
private final class BottomPanelIconComponent: Component {
|
||||
let imageName: String
|
||||
let title: String
|
||||
let isHighlighted: Bool
|
||||
let theme: PresentationTheme
|
||||
let action: () -> Void
|
||||
|
||||
init(
|
||||
imageName: String,
|
||||
title: String,
|
||||
isHighlighted: Bool,
|
||||
theme: PresentationTheme,
|
||||
action: @escaping () -> Void
|
||||
) {
|
||||
self.imageName = imageName
|
||||
self.title = title
|
||||
self.isHighlighted = isHighlighted
|
||||
self.theme = theme
|
||||
self.action = action
|
||||
}
|
||||
|
||||
static func ==(lhs: BottomPanelIconComponent, rhs: BottomPanelIconComponent) -> Bool {
|
||||
if lhs.imageName != rhs.imageName {
|
||||
if lhs.title != rhs.title {
|
||||
return false
|
||||
}
|
||||
if lhs.isHighlighted != rhs.isHighlighted {
|
||||
@ -67,13 +67,23 @@ private final class BottomPanelIconComponent: Component {
|
||||
}
|
||||
|
||||
func update(component: BottomPanelIconComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
if self.component?.imageName != component.imageName {
|
||||
self.contentView.image = UIImage(bundleImageName: component.imageName)
|
||||
if self.component?.title != component.title {
|
||||
let text = NSAttributedString(string: component.title, font: Font.medium(15.0), textColor: .white)
|
||||
let textBounds = text.boundingRect(with: CGSize(width: 120.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
|
||||
self.contentView.image = generateImage(CGSize(width: ceil(textBounds.width), height: ceil(textBounds.height)), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
UIGraphicsPushContext(context)
|
||||
text.draw(in: textBounds)
|
||||
UIGraphicsPopContext()
|
||||
})?.withRenderingMode(.alwaysTemplate)
|
||||
}
|
||||
|
||||
self.component = component
|
||||
|
||||
let size = CGSize(width: 28.0, height: 28.0)
|
||||
let textInset: CGFloat = 18.0
|
||||
|
||||
let textSize = self.contentView.image?.size ?? CGSize()
|
||||
let size = CGSize(width: textSize.width + textInset * 2.0, height: 28.0)
|
||||
|
||||
let color = component.isHighlighted ? component.theme.chat.inputMediaPanel.panelHighlightedIconColor : component.theme.chat.inputMediaPanel.panelIconColor
|
||||
|
||||
@ -87,8 +97,7 @@ private final class BottomPanelIconComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let contentSize = self.contentView.image?.size ?? size
|
||||
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(x: floor((size.width - contentSize.width) / 2.0), y: (size.height - contentSize.height) / 2.0), size: contentSize))
|
||||
transition.setFrame(view: self.contentView, frame: CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: (size.height - textSize.height) / 2.0 - 1.0), size: textSize))
|
||||
|
||||
return size
|
||||
}
|
||||
@ -304,7 +313,7 @@ final class EntityKeyboardBottomPanelComponent: Component {
|
||||
var iconInfos: [AnyHashable: (size: CGSize, transition: Transition)] = [:]
|
||||
|
||||
var iconTotalSize = CGSize()
|
||||
let iconSpacing: CGFloat = 22.0
|
||||
let iconSpacing: CGFloat = 4.0
|
||||
|
||||
let navigateToContentId = panelEnvironment.navigateToContentId
|
||||
|
||||
@ -326,7 +335,7 @@ final class EntityKeyboardBottomPanelComponent: Component {
|
||||
let iconSize = iconView.update(
|
||||
transition: iconTransition,
|
||||
component: AnyComponent(BottomPanelIconComponent(
|
||||
imageName: icon.imageName,
|
||||
title: icon.title,
|
||||
isHighlighted: icon.id == activeContentId,
|
||||
theme: component.theme,
|
||||
action: {
|
||||
@ -365,12 +374,7 @@ final class EntityKeyboardBottomPanelComponent: Component {
|
||||
self.highlightedIconBackgroundView.isHidden = false
|
||||
transition.setFrame(view: self.highlightedIconBackgroundView, frame: iconFrame)
|
||||
|
||||
let cornerRadius: CGFloat
|
||||
if icon.id == AnyHashable("emoji") {
|
||||
cornerRadius = min(iconFrame.width, iconFrame.height) / 2.0
|
||||
} else {
|
||||
cornerRadius = 10.0
|
||||
}
|
||||
let cornerRadius: CGFloat = min(iconFrame.width, iconFrame.height) / 2.0
|
||||
transition.setCornerRadius(layer: self.highlightedIconBackgroundView.layer, cornerRadius: cornerRadius)
|
||||
}
|
||||
|
||||
|
@ -139,17 +139,20 @@ public final class GifPagerContentComponent: Component {
|
||||
public let openGifContextMenu: (Item, UIView, CGRect, ContextGesture, Bool) -> Void
|
||||
public let loadMore: (String) -> Void
|
||||
public let openSearch: () -> Void
|
||||
public let updateSearchQuery: (String?) -> Void
|
||||
|
||||
public init(
|
||||
performItemAction: @escaping (Item, UIView, CGRect) -> Void,
|
||||
openGifContextMenu: @escaping (Item, UIView, CGRect, ContextGesture, Bool) -> Void,
|
||||
loadMore: @escaping (String) -> Void,
|
||||
openSearch: @escaping () -> Void
|
||||
openSearch: @escaping () -> Void,
|
||||
updateSearchQuery: @escaping (String?) -> Void
|
||||
) {
|
||||
self.performItemAction = performItemAction
|
||||
self.openGifContextMenu = openGifContextMenu
|
||||
self.loadMore = loadMore
|
||||
self.openSearch = openSearch
|
||||
self.updateSearchQuery = updateSearchQuery
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +187,7 @@ public final class GifPagerContentComponent: Component {
|
||||
public let isLoading: Bool
|
||||
public let loadMoreToken: String?
|
||||
public let displaySearchWithPlaceholder: String?
|
||||
public let searchCategories: EmojiSearchCategories?
|
||||
public let searchInitiallyHidden: Bool
|
||||
|
||||
public init(
|
||||
@ -194,6 +198,7 @@ public final class GifPagerContentComponent: Component {
|
||||
isLoading: Bool,
|
||||
loadMoreToken: String?,
|
||||
displaySearchWithPlaceholder: String?,
|
||||
searchCategories: EmojiSearchCategories?,
|
||||
searchInitiallyHidden: Bool
|
||||
) {
|
||||
self.context = context
|
||||
@ -203,6 +208,7 @@ public final class GifPagerContentComponent: Component {
|
||||
self.isLoading = isLoading
|
||||
self.loadMoreToken = loadMoreToken
|
||||
self.displaySearchWithPlaceholder = displaySearchWithPlaceholder
|
||||
self.searchCategories = searchCategories
|
||||
self.searchInitiallyHidden = searchInitiallyHidden
|
||||
}
|
||||
|
||||
@ -228,6 +234,9 @@ public final class GifPagerContentComponent: Component {
|
||||
if lhs.displaySearchWithPlaceholder != rhs.displaySearchWithPlaceholder {
|
||||
return false
|
||||
}
|
||||
if lhs.searchCategories != rhs.searchCategories {
|
||||
return false
|
||||
}
|
||||
if lhs.searchInitiallyHidden != rhs.searchInitiallyHidden {
|
||||
return false
|
||||
}
|
||||
@ -307,7 +316,7 @@ public final class GifPagerContentComponent: Component {
|
||||
|
||||
func visibleItems(for rect: CGRect) -> Range<Int>? {
|
||||
let offsetRect = rect.offsetBy(dx: -self.containerInsets.left, dy: -containerInsets.top)
|
||||
var minVisibleRow = Int(floor((offsetRect.minY - self.verticalSpacing) / (self.itemSize + self.verticalSpacing)))
|
||||
var minVisibleRow = Int(floor((offsetRect.minY - self.searchHeight - self.verticalSpacing) / (self.itemSize + self.verticalSpacing)))
|
||||
minVisibleRow = max(0, minVisibleRow)
|
||||
let maxVisibleRow = Int(ceil((offsetRect.maxY - self.verticalSpacing) / (self.itemSize + self.verticalSpacing)))
|
||||
|
||||
@ -430,6 +439,19 @@ public final class GifPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private final class SearchHeaderContainer: UIView {
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
var result: UIView?
|
||||
for subview in self.subviews.reversed() {
|
||||
if let value = subview.hitTest(self.convert(point, to: subview), with: event) {
|
||||
result = value
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public final class ContentScrollLayer: CALayer {
|
||||
public var mirrorLayer: CALayer?
|
||||
|
||||
@ -524,9 +546,12 @@ public final class GifPagerContentComponent: Component {
|
||||
private var vibrancyEffectView: UIVisualEffectView?
|
||||
private let mirrorContentScrollView: UIView
|
||||
private let scrollView: ContentScrollView
|
||||
private let scrollClippingView: UIView
|
||||
|
||||
private let placeholdersContainerView: UIView
|
||||
private var visibleSearchHeader: EmojiSearchHeaderView?
|
||||
private let searchHeaderContainer: SearchHeaderContainer
|
||||
private let mirrorSearchHeaderContainer: UIView
|
||||
private var visibleItemPlaceholderViews: [ItemKey: ItemPlaceholderView] = [:]
|
||||
private var visibleItemLayers: [ItemKey: ItemLayer] = [:]
|
||||
private var ignoreScrolling: Bool = false
|
||||
@ -552,6 +577,14 @@ public final class GifPagerContentComponent: Component {
|
||||
self.scrollView = ContentScrollView(mirrorView: self.mirrorContentScrollView)
|
||||
self.scrollView.layer.anchorPoint = CGPoint()
|
||||
|
||||
self.searchHeaderContainer = SearchHeaderContainer()
|
||||
self.searchHeaderContainer.layer.anchorPoint = CGPoint()
|
||||
self.mirrorSearchHeaderContainer = UIView()
|
||||
self.mirrorSearchHeaderContainer.layer.anchorPoint = CGPoint()
|
||||
|
||||
self.scrollClippingView = UIView()
|
||||
self.scrollClippingView.clipsToBounds = true
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
@ -570,9 +603,12 @@ public final class GifPagerContentComponent: Component {
|
||||
self.scrollView.showsHorizontalScrollIndicator = false
|
||||
self.scrollView.scrollsToTop = false
|
||||
self.scrollView.delegate = self
|
||||
self.addSubview(self.scrollView)
|
||||
|
||||
self.scrollClippingView.addSubview(self.scrollView)
|
||||
self.addSubview(self.scrollClippingView)
|
||||
|
||||
self.scrollView.addSubview(self.placeholdersContainerView)
|
||||
self.addSubview(self.searchHeaderContainer)
|
||||
|
||||
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||
|
||||
@ -665,7 +701,7 @@ public final class GifPagerContentComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
self.updateVisibleItems(attemptSynchronousLoads: false)
|
||||
self.updateVisibleItems(attemptSynchronousLoads: false, transition: .immediate, fromScrolling: true)
|
||||
|
||||
self.updateScrollingOffset(transition: .immediate)
|
||||
|
||||
@ -741,7 +777,7 @@ public final class GifPagerContentComponent: Component {
|
||||
self.updateScrollingOffset(transition: transition)
|
||||
}
|
||||
|
||||
private func updateVisibleItems(attemptSynchronousLoads: Bool) {
|
||||
private func updateVisibleItems(attemptSynchronousLoads: Bool, transition: Transition, fromScrolling: Bool) {
|
||||
guard let component = self.component, let itemLayout = self.itemLayout else {
|
||||
return
|
||||
}
|
||||
@ -776,7 +812,7 @@ public final class GifPagerContentComponent: Component {
|
||||
|
||||
let itemFrame = itemLayout.frame(at: index).offsetBy(dx: 0.0, dy: searchInset)
|
||||
|
||||
let itemTransition: Transition = .immediate
|
||||
var itemTransition: Transition = transition
|
||||
var updateItemLayerPlaceholder = false
|
||||
|
||||
let itemLayer: ItemLayer
|
||||
@ -784,6 +820,7 @@ public final class GifPagerContentComponent: Component {
|
||||
itemLayer = current
|
||||
} else {
|
||||
updateItemLayerPlaceholder = true
|
||||
itemTransition = .immediate
|
||||
|
||||
itemLayer = ItemLayer(
|
||||
item: item,
|
||||
@ -837,7 +874,10 @@ public final class GifPagerContentComponent: Component {
|
||||
let itemPosition = CGPoint(x: itemFrame.midX, y: itemFrame.midY)
|
||||
let itemBounds = CGRect(origin: CGPoint(), size: itemFrame.size)
|
||||
|
||||
itemTransition.setFrame(layer: itemLayer, frame: itemFrame)
|
||||
//itemTransition.setFrame(layer: itemLayer, frame: itemFrame)
|
||||
itemLayer.bounds = CGRect(origin: CGPoint(), size: itemFrame.size)
|
||||
itemTransition.setPosition(layer: itemLayer, position: itemFrame.center)
|
||||
|
||||
itemLayer.isVisibleForAnimations = true
|
||||
|
||||
if let placeholderView = self.visibleItemPlaceholderViews[itemId] {
|
||||
@ -871,6 +911,16 @@ public final class GifPagerContentComponent: Component {
|
||||
for id in removedIds {
|
||||
self.visibleItemLayers.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
transition.setPosition(view: self.searchHeaderContainer, position: self.scrollView.center)
|
||||
var searchContainerBounds = self.scrollView.bounds
|
||||
if case .emojiSearch = component.subject {
|
||||
searchContainerBounds.origin.y = 0.0
|
||||
}
|
||||
transition.setBounds(view: self.searchHeaderContainer, bounds: searchContainerBounds)
|
||||
|
||||
transition.setPosition(view: self.mirrorSearchHeaderContainer, position: self.scrollView.center)
|
||||
transition.setBounds(view: self.mirrorSearchHeaderContainer, bounds: searchContainerBounds)
|
||||
}
|
||||
|
||||
private func updateShimmerIfNeeded() {
|
||||
@ -900,6 +950,7 @@ public final class GifPagerContentComponent: Component {
|
||||
self.vibrancyEffectView = vibrancyEffectView
|
||||
self.backgroundView.addSubview(vibrancyEffectView)
|
||||
vibrancyEffectView.contentView.addSubview(self.mirrorContentScrollView)
|
||||
vibrancyEffectView.contentView.addSubview(self.mirrorSearchHeaderContainer)
|
||||
}
|
||||
}
|
||||
self.backgroundView.updateColor(color: theme.chat.inputMediaPanel.backgroundColor, enableBlur: true, forceKeepBlur: false, transition: transition.containedViewLayoutTransition)
|
||||
@ -965,30 +1016,45 @@ public final class GifPagerContentComponent: Component {
|
||||
if let current = self.visibleSearchHeader {
|
||||
visibleSearchHeader = current
|
||||
} else {
|
||||
visibleSearchHeader = EmojiSearchHeaderView(activated: { [weak self] in
|
||||
visibleSearchHeader = EmojiSearchHeaderView(activated: { [weak self] isTextInput in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.component?.inputInteraction.openSearch()
|
||||
if isTextInput {
|
||||
strongSelf.component?.inputInteraction.openSearch()
|
||||
}
|
||||
}, deactivated: { _ in
|
||||
}, updateQuery: { _ in
|
||||
}, updateQuery: { [weak self] query in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
switch query {
|
||||
case .none:
|
||||
component.inputInteraction.updateSearchQuery(nil)
|
||||
case .text:
|
||||
break
|
||||
case let .category(value):
|
||||
component.inputInteraction.updateSearchQuery(value)
|
||||
}
|
||||
})
|
||||
self.visibleSearchHeader = visibleSearchHeader
|
||||
self.scrollView.addSubview(visibleSearchHeader)
|
||||
self.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
|
||||
self.searchHeaderContainer.addSubview(visibleSearchHeader)
|
||||
self.mirrorSearchHeaderContainer.addSubview(visibleSearchHeader.tintContainerView)
|
||||
}
|
||||
|
||||
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: false, isActive: false, size: searchHeaderFrame.size, canFocus: false, searchCategories: nil, transition: transition)
|
||||
visibleSearchHeader.update(context: component.context, theme: keyboardChildEnvironment.theme, strings: keyboardChildEnvironment.strings, text: displaySearchWithPlaceholder, useOpaqueTheme: false, isActive: false, size: searchHeaderFrame.size, canFocus: false, searchCategories: component.searchCategories, transition: transition)
|
||||
transition.setFrame(view: visibleSearchHeader, frame: searchHeaderFrame, completion: { [weak self] completed in
|
||||
guard let strongSelf = self, completed, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
|
||||
let _ = self
|
||||
let _ = completed
|
||||
/*guard let strongSelf = self, completed, let visibleSearchHeader = strongSelf.visibleSearchHeader else {
|
||||
return
|
||||
}
|
||||
|
||||
if visibleSearchHeader.superview != strongSelf.scrollView {
|
||||
strongSelf.scrollView.addSubview(visibleSearchHeader)
|
||||
strongSelf.mirrorContentScrollView.addSubview(visibleSearchHeader.tintContainerView)
|
||||
}
|
||||
strongSelf.mirrorSearchHeaderContainer.addSubview(visibleSearchHeader.tintContainerView)
|
||||
}*/
|
||||
})
|
||||
} else {
|
||||
if let visibleSearchHeader = self.visibleSearchHeader {
|
||||
@ -998,7 +1064,15 @@ public final class GifPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
self.updateVisibleItems(attemptSynchronousLoads: true)
|
||||
self.updateVisibleItems(attemptSynchronousLoads: true, transition: transition, fromScrolling: false)
|
||||
|
||||
var clippingInset: CGFloat = 0.0
|
||||
if case .emojiSearch = component.subject {
|
||||
clippingInset = itemLayout.searchInsets.top + itemLayout.searchHeight - 1.0
|
||||
}
|
||||
let clippingFrame = CGRect(origin: CGPoint(x: 0.0, y: clippingInset), size: CGSize(width: availableSize.width, height: availableSize.height - clippingInset))
|
||||
transition.setPosition(view: self.scrollClippingView, position: clippingFrame.center)
|
||||
transition.setBounds(view: self.scrollClippingView, bounds: clippingFrame)
|
||||
|
||||
return availableSize
|
||||
}
|
||||
|
@ -468,7 +468,17 @@ final class DataUsageScreenComponent: Component {
|
||||
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 {
|
||||
animatedTransition.setAlpha(layer: backButtonNode.layer, alpha: navigationButtonAlpha)
|
||||
if backButtonNode.isHidden {
|
||||
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
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user