Various fixes

This commit is contained in:
Ilya Laktyushin 2022-11-07 17:34:04 +04:00
parent 5069754694
commit 6f08efd8ae
15 changed files with 186 additions and 142 deletions

View File

@ -8241,3 +8241,6 @@ Sorry for the inconvenience.";
"Attachment.DiscardPasteboardAlertText" = "Discard pasted items?";
"Undo.DeletedTopic" = "Topic Deleted";
"EmojiSearch.SearchTopicIconsPlaceholder" = "Search Topic Icons";
"EmojiSearch.SearchTopicIconsEmptyResult" = "No emoji found";

View File

@ -524,9 +524,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
default:
let actionTitle: String
if channel.flags.contains(.requestToJoin) {
actionTitle = strongSelf.presentationData.strings.Channel_JoinChannel
} else {
actionTitle = strongSelf.presentationData.strings.Group_ApplyToJoin
} else {
actionTitle = strongSelf.presentationData.strings.Channel_JoinChannel
}
strongSelf.setToolbar(Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: actionTitle, isEnabled: true)), transition: .animated(duration: 0.4, curve: .spring))
}
@ -1871,10 +1871,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
self.tabContainerNode.presentPremiumTip = { [weak self] in
if let strongSelf = self {
let context = strongSelf.context
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_reorder", scale: 0.05, colors: [:], title: nil, text: strongSelf.presentationData.strings.ChatListFolderSettings_SubscribeToMoveAll, customUndoText: strongSelf.presentationData.strings.ChatListFolderSettings_SubscribeToMoveAllAction), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { action in
if case .undo = action {
strongSelf.push(PremiumIntroScreen(context: context, source: .folders))
let context = strongSelf.context
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumDemoScreen(context: context, subject: .advancedChatManagement, action: {
let controller = PremiumIntroScreen(context: context, source: .folders)
replaceImpl?(controller)
})
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
strongSelf.push(controller)
}
return false }), in: .current)
}
@ -2980,6 +2988,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
displaySearchFilters = false
}
if !tabsIsEmpty, let snapshotView = strongSelf.tabContainerNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = strongSelf.tabContainerNode.frame
strongSelf.tabContainerNode.view.superview?.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
if let searchContentNode = strongSelf.searchContentNode {
if let filterContainerNodeAndActivate = strongSelf.chatListDisplayNode.activateSearch(placeholderNode: searchContentNode.placeholderNode, displaySearchFilters: displaySearchFilters, hasDownloads: strongSelf.hasDownloads, initialFilter: filter, navigationController: strongSelf.navigationController as? NavigationController) {
let (filterContainerNode, activate) = filterContainerNodeAndActivate
@ -2996,13 +3013,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
searchContentNode.search(filter: filter, query: query)
}
if !tabsIsEmpty {
Queue.mainQueue().after(0.01) {
filterContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 38.0), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
filterContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
strongSelf.tabContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -64.0), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
Queue.mainQueue().justDispatch {
filterContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 30.0), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
filterContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
}
}
@ -3033,15 +3046,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
if !self.displayNavigationBar {
var completion: (() -> Void)?
var filterContainerNode: ASDisplayNode?
if animated, let searchContentNode = self.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
filterContainerNode = searchContentNode.filterContainerNode
}
if let searchContentNode = self.searchContentNode {
completion = self.chatListDisplayNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode, animated: animated)
}
let tabsIsEmpty: Bool
if let (resolvedItems, displayTabsAtBottom, _) = self.tabContainerData {
tabsIsEmpty = resolvedItems.count <= 1 || displayTabsAtBottom
@ -3049,6 +3053,33 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
tabsIsEmpty = true
}
var filterContainerNode: ASDisplayNode?
if animated, let searchContentNode = self.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
filterContainerNode = searchContentNode.filterContainerNode
if let filterContainerNode = filterContainerNode, let snapshotView = filterContainerNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = filterContainerNode.frame
filterContainerNode.view.superview?.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
if !tabsIsEmpty {
Queue.mainQueue().after(0.01) {
self.tabContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.tabContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -74.0), to: .zero, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
}
}
}
if let searchContentNode = self.searchContentNode {
completion = self.chatListDisplayNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode, animated: animated)
}
self.navigationBar?.setSecondaryContentNode(tabsIsEmpty ? nil : self.tabContainerNode, animated: false)
if let parentController = self.parent as? TabBarController {
parentController.navigationBar?.setSecondaryContentNode(tabsIsEmpty ? nil : self.tabContainerNode, animated: animated)
@ -3061,14 +3092,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
(self.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.4, curve: .spring))
if let filterContainerNode = filterContainerNode {
filterContainerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -44.0), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
if !tabsIsEmpty {
self.tabContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -64.0), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
}
self.isSearchActive = false
if let navigationController = self.navigationController as? NavigationController {
for controller in navigationController.globalOverlayControllers {

View File

@ -473,7 +473,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
private(set) var transitionFraction: CGFloat = 0.0
private var transitionFractionOffset: CGFloat = 0.0
private var disableItemNodeOperationsWhileAnimating: Bool = false
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, isReorderingFilters: Bool, isEditing: Bool)?
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool)?
private var enableAdjacentFilterLoading: Bool = false
@ -714,7 +714,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
self.onFilterSwitch?()
self.transitionFractionOffset = 0.0
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] {
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout, let itemNode = self.itemNodes[self.selectedId] {
for (id, itemNode) in self.itemNodes {
if id != selectedId {
itemNode.emptyNode?.restartAnimation()
@ -727,13 +727,13 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
for (_, itemNode) in self.itemNodes {
itemNode.layer.removeAllAnimations()
}
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, .immediate, true)
}
}
}
case .changed:
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) {
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) {
let translation = recognizer.translation(in: self.view)
var transitionFraction = translation.x / layout.size.width
@ -770,11 +770,11 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
}
}
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, .immediate, false)
}
case .cancelled, .ended:
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) {
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout, let selectedIndex = self.availableFilters.firstIndex(where: { $0.id == self.selectedId }) {
let translation = recognizer.translation(in: self.view)
let velocity = recognizer.velocity(in: self.view)
var directionIsToRight: Bool?
@ -813,12 +813,12 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
self.transitionFraction = 0.0
let transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring)
self.disableItemNodeOperationsWhileAnimating = true
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: transition)
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: transition)
self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, transition, false)
DispatchQueue.main.async {
self.disableItemNodeOperationsWhileAnimating = false
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout {
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout {
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
}
}
}
@ -884,8 +884,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
strongSelf.availableFilters = availableFilters
strongSelf.filtersLimit = limit
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = strongSelf.validLayout {
strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
if let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = strongSelf.validLayout {
strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
}
}
if !availableFilters.contains(where: { $0.id == self.selectedId }) {
@ -902,8 +902,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
if value != self.enableAdjacentFilterLoading {
self.enableAdjacentFilterLoading = value
if self.enableAdjacentFilterLoading, let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout {
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
if self.enableAdjacentFilterLoading, let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout {
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
}
}
}
@ -912,7 +912,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
self.onFilterSwitch?()
if id != self.selectedId, let index = self.availableFilters.firstIndex(where: { $0.id == id }) {
if let itemNode = self.itemNodes[id] {
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = self.validLayout else {
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = self.validLayout else {
return
}
self.selectedId = id
@ -921,7 +921,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
self.applyItemNodeAsCurrent(id: id, itemNode: itemNode)
let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .spring)
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: transition)
self.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: transition)
self.currentItemFilterUpdated?(self.currentItemFilter, self.transitionFraction, transition, false)
itemNode.emptyNode?.restartAnimation()
completion?()
@ -951,7 +951,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
strongSelf.pendingItemNode = nil
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing) = strongSelf.validLayout else {
guard let (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing) = strongSelf.validLayout else {
strongSelf.itemNodes[id] = itemNode
strongSelf.addSubnode(itemNode)
@ -999,13 +999,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
itemNode.frame = itemFrame
transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: -offset, y: 0.0))
var insets = layout.insets(options: [.input])
insets.top += navigationBarHeight
insets.left += layout.safeInsets.left
insets.right += layout.safeInsets.right
itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, transition: .immediate)
strongSelf.selectedId = id
@ -1014,7 +1008,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
strongSelf.applyItemNodeAsCurrent(id: id, itemNode: itemNode)
strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
strongSelf.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: isReorderingFilters, isEditing: isEditing, transition: .immediate)
strongSelf.currentItemFilterUpdated?(strongSelf.currentItemFilter, strongSelf.transitionFraction, transition, false)
}
@ -1025,25 +1019,11 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
}
}
func update(layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, isReorderingFilters: Bool, isEditing: Bool, transition: ContainedViewLayoutTransition) {
self.validLayout = (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, isReorderingFilters, isEditing)
func update(layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, transition: ContainedViewLayoutTransition) {
self.validLayout = (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing)
self._validLayoutReady.set(.single(true))
var insets = layout.insets(options: [.input])
insets.top += navigationBarHeight
insets.left += layout.safeInsets.left
insets.right += layout.safeInsets.right
if isEditing {
if !layout.safeInsets.left.isZero {
insets.bottom += 34.0
} else {
insets.bottom += 49.0
}
}
transition.updateAlpha(node: self, alpha: isReorderingFilters ? 0.5 : 1.0)
self.isUserInteractionEnabled = !isReorderingFilters
@ -1264,20 +1244,26 @@ final class ChatListControllerNode: ASDisplayNode {
if layout.metrics.widthClass == .regular {
options.insert(.input)
}
var heightInset: CGFloat = 0.0
if case .forum = self.location {
heightInset = 4.0
}
let bottomInset: CGFloat = layout.insets(options: options).bottom
if !layout.safeInsets.left.isZero {
tabBarHeight = 34.0 + bottomInset
insets.bottom += 34.0
} else {
tabBarHeight = 49.0 + bottomInset
insets.bottom += 49.0
tabBarHeight = 49.0 - heightInset + bottomInset
insets.bottom += 49.0 - heightInset
}
let tabBarFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - tabBarHeight), size: CGSize(width: layout.size.width, height: tabBarHeight))
let toolbarFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - tabBarHeight), size: CGSize(width: layout.size.width, height: tabBarHeight))
if let toolbarNode = self.toolbarNode {
transition.updateFrame(node: toolbarNode, frame: tabBarFrame)
toolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: toolbar, transition: transition)
transition.updateFrame(node: toolbarNode, frame: toolbarFrame)
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: toolbar, transition: transition)
} else {
let toolbarNode = ToolbarNode(theme: ToolbarTheme(rootControllerTheme: self.presentationData.theme), displaySeparator: true, left: { [weak self] in
self?.toolbarActionSelected?(.left)
@ -1286,8 +1272,8 @@ final class ChatListControllerNode: ASDisplayNode {
}, middle: { [weak self] in
self?.toolbarActionSelected?(.middle)
})
toolbarNode.frame = tabBarFrame
toolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: toolbar, transition: .immediate)
toolbarNode.frame = toolbarFrame
toolbarNode.updateLayout(size: toolbarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: toolbar, transition: .immediate)
self.addSubnode(toolbarNode)
self.toolbarNode = toolbarNode
if transition.isAnimated {
@ -1306,7 +1292,7 @@ final class ChatListControllerNode: ASDisplayNode {
self.controller?.presentationContext.containerLayoutUpdated(childrenLayout, transition: transition)
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: layout.size))
self.containerNode.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, transition: transition)
self.containerNode.update(layout: layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: insets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, transition: transition)
transition.updateFrame(node: self.inlineTabContainerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - layout.intrinsicInsets.bottom - 8.0 - 40.0), size: CGSize(width: layout.size.width, height: 40.0)))

View File

@ -2211,7 +2211,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let avatarIconContent: EmojiStatusComponent.Content
if let fileId = threadInfo.info.icon, fileId != 0 {
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .forever)
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
} else {
avatarIconContent = .topic(title: String(threadInfo.info.title.prefix(1)), color: threadInfo.info.iconColor, size: CGSize(width: 32.0, height: 32.0))
}

View File

@ -407,7 +407,7 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
}
}
private var tokensWidth: CGFloat = 0.0
fileprivate var tokensWidth: CGFloat = 0.0
private let measurePrefixLabel: ImmediateTextNode
let prefixLabel: ImmediateTextNode
@ -569,19 +569,24 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
textOffset += 2.0
}
var placeholderOffset: CGFloat = 0.0
var placeholderXOffset: CGFloat = 0.0
if self.tokensWidth > 0.0, self.scrollView?.superview != nil {
placeholderXOffset = self.tokensWidth + 8.0
}
var placeholderYOffset: CGFloat = 0.0
if #available(iOS 14.0, *) {
placeholderOffset = 1.0
placeholderYOffset = 1.0
} else {
}
let textRect = self.textRect(forBounds: bounds)
let labelSize = self.placeholderLabel.updateLayout(textRect.size)
self.placeholderLabel.frame = CGRect(origin: CGPoint(x: textRect.minX, y: textRect.minY + textOffset + placeholderOffset), size: labelSize)
self.placeholderLabel.frame = CGRect(origin: CGPoint(x: textRect.minX + placeholderXOffset, y: textRect.minY + textOffset + placeholderYOffset), size: labelSize)
let prefixSize = self.prefixLabel.updateLayout(CGSize(width: floor(bounds.size.width * 0.7), height: bounds.size.height))
let prefixBounds = bounds.insetBy(dx: 4.0, dy: 4.0)
self.prefixLabel.frame = CGRect(origin: CGPoint(x: prefixBounds.minX, y: prefixBounds.minY + textOffset + placeholderOffset), size: prefixSize)
self.prefixLabel.frame = CGRect(origin: CGPoint(x: prefixBounds.minX, y: prefixBounds.minY + textOffset + placeholderYOffset), size: prefixSize)
}
override func deleteBackward() {
@ -1027,7 +1032,12 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
self.textBackgroundNode.layer.animateFrame(from: initialTextBackgroundFrame, to: self.textBackgroundNode.frame, duration: duration, timingFunction: timingFunction)
let textFieldFrame = self.textField.frame
let initialLabelNodeFrame = CGRect(origin: node.labelNode.frame.offsetBy(dx: initialTextBackgroundFrame.origin.x - 7.0, dy: initialTextBackgroundFrame.origin.y - 8.0).origin, size: textFieldFrame.size)
var tokensWidth = self.textField.tokensWidth
if tokensWidth > 0.0 {
tokensWidth += 8.0
}
let initialLabelNodeFrame = CGRect(origin: node.labelNode.frame.offsetBy(dx: initialTextBackgroundFrame.origin.x - 7.0 - tokensWidth, dy: initialTextBackgroundFrame.origin.y - 8.0).origin, size: textFieldFrame.size)
self.textField.layer.animateFrame(from: initialLabelNodeFrame, to: self.textField.frame, duration: duration, timingFunction: timingFunction)
let iconFrame = self.iconNode.frame
@ -1056,13 +1066,54 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
let timingFunction = kCAMediaTimingFunctionSpring
node.isHidden = true
self.clearButton.isHidden = true
if !self.clearButton.isHidden {
let xOffset = targetTextBackgroundFrame.width - self.textBackgroundNode.frame.width
if !xOffset.isZero {
self.clearButton.layer.animatePosition(from: .zero, to: CGPoint(x: xOffset, y: 0.0), duration: duration, timingFunction: timingFunction, additive: true)
}
self.clearButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { _ in
self.clearButton.isHidden = true
})
}
self.activityIndicator?.isHidden = true
self.iconNode.isHidden = false
var tokensWidth = self.textField.tokensWidth
if tokensWidth > 0.0 {
tokensWidth += 8.0
}
let textFieldFrame = self.textField.frame
let targetLabelNodeFrame = CGRect(origin: CGPoint(x: node.labelNode.frame.minX + targetTextBackgroundFrame.origin.x - 7.0 - tokensWidth, y: targetTextBackgroundFrame.minY + floorToScreenPixels((targetTextBackgroundFrame.size.height - textFieldFrame.size.height) / 2.0) - UIScreenPixel), size: textFieldFrame.size)
self.textField.layer.animateFrame(from: textFieldFrame, to: targetLabelNodeFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
if !self.textField.tokenNodes.isEmpty {
for node in self.textField.tokenNodes.values {
node.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
}
}
var hasText = false
if !(self.textField.text ?? "").isEmpty, let snapshotView = self.textField.snapshotView(afterScreenUpdates: false) {
hasText = true
snapshotView.frame = self.textField.frame
self.textField.superview?.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
snapshotView.removeFromSuperview()
})
snapshotView.layer.animatePosition(from: .zero, to: CGPoint(x: targetLabelNodeFrame.minX - textFieldFrame.minX, y: 0.0), duration: duration, timingFunction: timingFunction, removeOnCompletion: false, additive: true)
self.textField.placeholderLabel.alpha = 0.0
}
self.textField.prefixString = nil
self.textField.text = ""
self.textField.layoutSubviews()
var backgroundCompleted = false
var separatorCompleted = false
var textBackgroundCompleted = false
@ -1123,34 +1174,18 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
transitionBackgroundNode.backgroundColor = node.backgroundNode.backgroundColor
transitionBackgroundNode.cornerRadius = node.backgroundNode.cornerRadius
self.insertSubnode(transitionBackgroundNode, aboveSubnode: self.textBackgroundNode)
//transitionBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration / 2.0, removeOnCompletion: false)
transitionBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
let textFieldFrame = self.textField.frame
let targetLabelNodeFrame = CGRect(origin: CGPoint(x: node.labelNode.frame.minX + targetTextBackgroundFrame.origin.x - 7.0, y: targetTextBackgroundFrame.minY + floorToScreenPixels((targetTextBackgroundFrame.size.height - textFieldFrame.size.height) / 2.0) - UIScreenPixel), size: textFieldFrame.size)
self.textField.layer.animateFrame(from: self.textField.frame, to: targetLabelNodeFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
if let snapshot = node.labelNode.layer.snapshotContentTree() {
snapshot.frame = CGRect(origin: self.textField.placeholderLabel.frame.origin.offsetBy(dx: 0.0, dy: UIScreenPixel), size: node.labelNode.frame.size)
self.textField.layer.addSublayer(snapshot)
snapshot.animateAlpha(from: 0.0, to: 1.0, duration: duration * 2.0 / 3.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue)
transitionBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
if let snapshot = node.labelNode.layer.snapshotContentTree() {
snapshot.frame = CGRect(origin: self.textField.placeholderLabel.frame.origin.offsetBy(dx: 0.0, dy: UIScreenPixel), size: node.labelNode.frame.size)
self.textField.layer.addSublayer(snapshot)
snapshot.animateAlpha(from: 0.0, to: 1.0, duration: duration * 2.0 / 3.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue)
if !hasText {
self.textField.placeholderLabel.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false)
}
} else if let cachedLayout = node.labelNode.cachedLayout {
let labelNode = TextNode()
labelNode.isOpaque = false
labelNode.isUserInteractionEnabled = false
let labelLayout = TextNode.asyncLayout(labelNode)
let (labelLayoutResult, labelApply) = labelLayout(TextNodeLayoutArguments(attributedString: self.placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: cachedLayout.size, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let _ = labelApply()
self.textField.addSubnode(labelNode)
labelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration * 2.0 / 3.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue)
labelNode.frame = CGRect(origin: self.textField.placeholderLabel.frame.origin.offsetBy(dx: 0.0, dy: UIScreenPixel), size: labelLayoutResult.size)
self.textField.placeholderLabel.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { _ in
labelNode.removeFromSupernode()
})
}
let iconFrame = self.iconNode.frame
let targetIconFrame = CGRect(origin: node.iconNode.frame.offsetBy(dx: targetTextBackgroundFrame.origin.x, dy: targetTextBackgroundFrame.origin.y).origin, size: iconFrame.size)
self.iconNode.image = node.iconNode.image
@ -1216,13 +1251,6 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
}
private func updateIsEmpty(animated: Bool = false) {
let textIsEmpty = (self.textField.text?.isEmpty ?? true)
let isEmpty = textIsEmpty && self.tokens.isEmpty
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
let placeholderTransition = !isEmpty ? .immediate : transition
placeholderTransition.updateAlpha(node: self.textField.placeholderLabel, alpha: isEmpty ? 1.0 : 0.0)
var tokensEmpty = true
for token in self.tokens {
if !token.permanent {
@ -1230,6 +1258,13 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
}
}
let textIsEmpty = (self.textField.text?.isEmpty ?? true)
let isEmpty = textIsEmpty && tokensEmpty
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
let placeholderTransition = !isEmpty ? .immediate : transition
placeholderTransition.updateAlpha(node: self.textField.placeholderLabel, alpha: isEmpty ? 1.0 : 0.0)
let clearIsHidden = (textIsEmpty && tokensEmpty) && self.prefixString == nil
transition.updateAlpha(node: self.clearButton.imageNode, alpha: clearIsHidden ? 0.0 : 1.0)
transition.updateTransformScale(node: self.clearButton, scale: clearIsHidden ? 0.2 : 1.0)

View File

@ -200,7 +200,7 @@ public final class SearchDisplayController {
if !self.contentNode.hasDim {
self.backgroundNode.alpha = 1.0
self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, timingFunction: CAMediaTimingFunctionName.linear.rawValue)
self.backgroundNode.layer.animateScale(from: 0.85, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
}
@ -259,7 +259,7 @@ public final class SearchDisplayController {
}
public func deactivate(placeholder: SearchBarPlaceholderNode?, animated: Bool = true) {
self.searchBar.deactivate()
self.searchBar.deactivate(clear: false)
let searchBar = self.searchBar
if let placeholder = placeholder {

View File

@ -718,7 +718,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
if self.titleRightIconNode.supernode == nil {
self.titleTextNode.addSubnode(self.titleRightIconNode)
}
rightIconWidth = image.size.width + 3.0
rightIconWidth = max(24.0, image.size.width) + 3.0
} else if self.titleRightIconNode.supernode != nil {
self.titleRightIconNode.removeFromSupernode()
}

View File

@ -63,9 +63,9 @@ public func generateTopicIcon(title: String, backgroundColors: [UIColor], stroke
let attributedString = NSAttributedString(string: title, attributes: [NSAttributedString.Key.font: Font.with(size: fontSize, design: .round, weight: .bold), NSAttributedString.Key.foregroundColor: UIColor.white])
let line = CTLineCreateWithAttributedString(attributedString)
let lineBounds = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
let lineBounds = CTLineGetBoundsWithOptions(line, [.useOpticalBounds])
let lineOffset = CGPoint(x: title == "B" ? 1.0 : 0.0, y: floorToScreenPixels(realSize.height * 0.05))
let lineOffset = CGPoint(x: 1.0 - UIScreenPixel, y: floorToScreenPixels(realSize.height * 0.05))
let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (realSize.width - lineBounds.size.width) / 2.0) + lineOffset.x, y: floorToScreenPixels(-lineBounds.origin.y + (realSize.height - lineBounds.size.height) / 2.0) + lineOffset.y)
context.translateBy(x: realSize.width / 2.0, y: realSize.height / 2.0)

View File

@ -6916,6 +6916,8 @@ public final class EmojiPagerContentComponent: Component {
displaySearchWithPlaceholder = strings.EmojiSearch_SearchReactionsPlaceholder
} else if isStatusSelection {
displaySearchWithPlaceholder = strings.EmojiSearch_SearchStatusesPlaceholder
} else if isTopicIconSelection {
displaySearchWithPlaceholder = strings.EmojiSearch_SearchTopicIconsPlaceholder
}
return EmojiPagerContentComponent(
@ -7014,8 +7016,7 @@ func generateTopicIcon(backgroundColors: [UIColor], strokeColors: [UIColor], tit
let line = CTLineCreateWithAttributedString(attributedString)
let lineBounds = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds)
let lineOffset = CGPoint(x: title == "B" ? 1.0 : 0.0, y: 0.0)
let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (size.width - lineBounds.size.width) / 2.0) + lineOffset.x, y: floorToScreenPixels(-lineBounds.origin.y + (size.height - lineBounds.size.height) / 2.0) + 1.0)
let lineOrigin = CGPoint(x: floorToScreenPixels(-lineBounds.origin.x + (size.width - lineBounds.size.width) / 2.0), y: floorToScreenPixels(-lineBounds.origin.y + (size.height - lineBounds.size.height) / 2.0) + 1.0)
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.scaleBy(x: 1.0, y: -1.0)

View File

@ -85,7 +85,11 @@ private func actionForPeer(peer: Peer, interfaceState: ChatPresentationInterface
if channel.flags.contains(.requestToJoin) {
return .applyToJoin
} else {
return .joinGroup
if channel.flags.contains(.isForum) {
return .join
} else {
return .joinGroup
}
}
} else {
return .join

View File

@ -4924,7 +4924,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let avatarContent: EmojiStatusComponent.Content
if let fileId = threadInfo.icon {
avatarContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: strongSelf.presentationData.theme.list.mediaPlaceholderColor, themeColor: strongSelf.presentationData.theme.list.itemAccentColor, loopMode: .count(2))
avatarContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: strongSelf.presentationData.theme.list.mediaPlaceholderColor, themeColor: strongSelf.presentationData.theme.list.itemAccentColor, loopMode: .count(1))
} else {
avatarContent = .topic(title: String(threadInfo.title.prefix(1)), color: threadInfo.iconColor, size: CGSize(width: 32.0, height: 32.0))
}

View File

@ -896,7 +896,7 @@ private enum ChatEmptyNodeContentType: Equatable {
case cloud
case peerNearby
case greeting
case topic(Int64?)
case topic
}
final class ChatEmptyNode: ASDisplayNode {
@ -973,7 +973,7 @@ final class ChatEmptyNode: ASDisplayNode {
let contentType: ChatEmptyNodeContentType
if case .replyThread = interfaceState.chatLocation {
if case .topic = emptyType {
contentType = .topic(nil)
contentType = .topic
} else {
contentType = .regular
}

View File

@ -2765,7 +2765,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} else if action.action == .historyCleared {
emptyType = .clearedHistory
break
} else if case .topicCreated = action.action {
} else if case .topicCreated = action.action, firstEntry.message.author?.id == strongSelf.context.account.peerId {
emptyType = .topic
break
}

View File

@ -152,13 +152,13 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
isMember = true
case .left:
if case .replyThread = chatPresentationInterfaceState.chatLocation {
if !channel.flags.contains(.joinToSend) {
if !channel.flags.contains(.joinToSend) && !channel.flags.contains(.isForum) {
isMember = true
}
}
}
if channel.flags.contains(.isForum) {
if channel.flags.contains(.isForum) && isMember {
if let threadData = chatPresentationInterfaceState.threadData {
if threadData.isClosed {
var canManage = false

View File

@ -1396,17 +1396,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
authorRank = attributes.rank
}
var enableAutoRank = false
if let authorRank = authorRank, case .admin = authorRank {
enableAutoRank = true
} else if authorRank == nil {
enableAutoRank = true
}
if enableAutoRank {
if let topicAuthorId = item.associatedData.topicAuthorId, topicAuthorId == message.author?.id {
authorRank = .custom(item.presentationData.strings.Chat_Message_TopicAuthorBadge)
}
if authorRank == nil, let topicAuthorId = item.associatedData.topicAuthorId, topicAuthorId == message.author?.id {
authorRank = .custom(item.presentationData.strings.Chat_Message_TopicAuthorBadge)
}
case .group:
break