diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index de49eaedb7..2a962ec194 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -362,6 +362,7 @@ private final class ChatListContainerItemNode: ASDisplayNode { private var canReportPeer: Bool = false private(set) var validLayout: (size: CGSize, insets: UIEdgeInsets, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat, storiesInset: CGFloat)? + private var scrollingOffset: (navigationHeight: CGFloat, offset: CGFloat)? init(context: AccountContext, controller: ChatListControllerImpl?, location: ChatListControllerLocation, filter: ChatListFilter?, chatListMode: ChatListNodeMode, previewing: Bool, isInlineMode: Bool, controlsHistoryPreload: Bool, presentationData: PresentationData, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void, secondaryEmptyAction: @escaping () -> Void, openArchiveSettings: @escaping () -> Void, autoSetReady: Bool) { self.context = context @@ -454,9 +455,13 @@ private final class ChatListContainerItemNode: ASDisplayNode { strongSelf.emptyNode = emptyNode strongSelf.listNode.addSubnode(emptyNode) if let (size, insets, _, _, _, _, _) = strongSelf.validLayout { - let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) + let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)) emptyNode.frame = emptyNodeFrame - emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate) + emptyNode.updateLayout(size: size, insets: insets, transition: .immediate) + + if let scrollingOffset = strongSelf.scrollingOffset { + emptyNode.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: .immediate) + } } emptyNode.alpha = 0.0 transition.updateAlpha(node: emptyNode, alpha: 1.0) @@ -736,13 +741,25 @@ private final class ChatListContainerItemNode: ASDisplayNode { self.listNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, visibleTopInset: visualNavigationHeight + additionalTopInset, originalTopInset: originalNavigationHeight + additionalTopInset, storiesInset: storiesInset, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction) if let emptyNode = self.emptyNode { - let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: listInsets.top), size: CGSize(width: size.width, height: size.height - listInsets.top - listInsets.bottom)) + let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)) transition.updateFrame(node: emptyNode, frame: emptyNodeFrame) - emptyNode.updateLayout(size: emptyNodeFrame.size, transition: transition) + emptyNode.updateLayout(size: emptyNodeFrame.size, insets: listInsets, transition: transition) + + if let scrollingOffset = self.scrollingOffset { + emptyNode.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: transition) + } } self.layoutAdditionalPanels(transition: transition) } + + func updateScrollingOffset(navigationHeight: CGFloat, offset: CGFloat, transition: ContainedViewLayoutTransition) { + self.scrollingOffset = (navigationHeight, offset) + + if let emptyNode = self.emptyNode { + emptyNode.updateScrollingOffset(navigationHeight: navigationHeight, offset: offset, transition: transition) + } + } } public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate { @@ -804,6 +821,8 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele private var disableItemNodeOperationsWhileAnimating: Bool = false private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat, storiesInset: CGFloat)? + private var scrollingOffset: (navigationHeight: CGFloat, offset: CGFloat)? + private var enableAdjacentFilterLoading: Bool = false private var panRecognizer: InteractiveTransitionGestureRecognizer? @@ -1551,6 +1570,9 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele transition.animatePositionAdditive(node: itemNode, offset: CGPoint(x: -offset, y: 0.0)) itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, storiesInset: storiesInset, transition: .immediate) + if let scrollingOffset = strongSelf.scrollingOffset { + itemNode.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: .immediate) + } strongSelf.selectedId = id if let currentItemNode = strongSelf.currentItemNodeValue { @@ -1568,12 +1590,23 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele if let (layout, _, visualNavigationHeight, originalNavigationHeight, _, insets, _, _, inlineNavigationLocation, inlineNavigationTransitionFraction, storiesInset) = self.validLayout { itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: inlineNavigationTransitionFraction, storiesInset: storiesInset, transition: .immediate) + + if let scrollingOffset = self.scrollingOffset { + itemNode.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: .immediate) + } return } } } } + func updateScrollingOffset(navigationHeight: CGFloat, offset: CGFloat, transition: ContainedViewLayoutTransition) { + self.scrollingOffset = (navigationHeight, offset) + for (_, itemNode) in self.itemNodes { + itemNode.updateScrollingOffset(navigationHeight: navigationHeight, offset: offset, transition: transition) + } + } + public func update(layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, originalNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, insets: UIEdgeInsets, isReorderingFilters: Bool, isEditing: Bool, inlineNavigationLocation: ChatListControllerLocation?, inlineNavigationTransitionFraction: CGFloat, storiesInset: CGFloat, transition: ContainedViewLayoutTransition) { self.validLayout = (layout, navigationBarHeight, visualNavigationHeight, originalNavigationHeight, cleanNavigationBarHeight, insets, isReorderingFilters, isEditing, inlineNavigationLocation, inlineNavigationTransitionFraction, storiesInset) @@ -1647,6 +1680,9 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele } itemNode.updateLayout(size: layout.size, insets: insets, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: originalNavigationHeight, inlineNavigationLocation: inlineNavigationLocation, inlineNavigationTransitionFraction: itemInlineNavigationTransitionFraction, storiesInset: storiesInset, transition: nodeTransition) + if let scrollingOffset = self.scrollingOffset { + itemNode.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: nodeTransition) + } if wasAdded, case .animated = transition { animateSlidingIds.append(id) @@ -2041,6 +2077,9 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { } else { mainOffset = navigationHeight } + + self.mainContainerNode.updateScrollingOffset(navigationHeight: navigationHeight, offset: mainOffset, transition: transition) + mainOffset = min(mainOffset, ChatListNavigationBar.searchScrollHeight) if abs(mainOffset) < 0.1 { mainOffset = 0.0 @@ -2354,11 +2393,6 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate { guard let containerLayout = self.containerLayout else { return } - let _ = containerLayout - if let inlineStackContainerNode = self.inlineStackContainerNode { - let _ = inlineStackContainerNode - } - self.updateNavigationScrolling(navigationHeight: containerLayout.navigationBarHeight, transition: self.tempNavigationScrollingTransition ?? .immediate) } diff --git a/submodules/ChatListUI/Sources/ChatListEmptyNode.swift b/submodules/ChatListUI/Sources/ChatListEmptyNode.swift index d43de75134..0d7d7bf74a 100644 --- a/submodules/ChatListUI/Sources/ChatListEmptyNode.swift +++ b/submodules/ChatListUI/Sources/ChatListEmptyNode.swift @@ -14,6 +14,7 @@ import ComponentFlow import ArchiveInfoScreen import ComponentDisplayAdapters import SwiftSignalKit +import ChatListHeaderComponent final class ChatListEmptyNode: ASDisplayNode { enum Subject { @@ -44,7 +45,8 @@ final class ChatListEmptyNode: ASDisplayNode { private var animationSize: CGSize = CGSize() private var buttonIsHidden: Bool - private var validLayout: CGSize? + private var validLayout: (size: CGSize, insets: UIEdgeInsets)? + private var scrollingOffset: (navigationHeight: CGFloat, offset: CGFloat)? private var globalPrivacySettings: GlobalPrivacySettings = .default private var archiveSettingsDisposable: Disposable? @@ -144,8 +146,8 @@ final class ChatListEmptyNode: ASDisplayNode { return } self.globalPrivacySettings = settings - if let size = self.validLayout { - self.updateLayout(size: size, transition: .immediate) + if let (size, insets) = self.validLayout { + self.updateLayout(size: size, insets: insets, transition: .immediate) } }) } @@ -213,8 +215,12 @@ final class ChatListEmptyNode: ASDisplayNode { self.activityIndicator.type = .custom(theme.list.itemAccentColor, 22.0, 1.0, false) - if let size = self.validLayout { - self.updateLayout(size: size, transition: .immediate) + if let (size, insets) = self.validLayout { + self.updateLayout(size: size, insets: insets, transition: .immediate) + + if let scrollingOffset = self.scrollingOffset { + self.updateScrollingOffset(navigationHeight: scrollingOffset.navigationHeight, offset: scrollingOffset.offset, transition: .immediate) + } } } @@ -230,44 +236,8 @@ final class ChatListEmptyNode: ASDisplayNode { self.activityIndicator.isHidden = !self.isLoading } - func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { - self.validLayout = size - - if case .archive = self.subject { - let emptyArchive: ComponentView - if let current = self.emptyArchive { - emptyArchive = current - } else { - emptyArchive = ComponentView() - self.emptyArchive = emptyArchive - } - let emptyArchiveSize = emptyArchive.update( - transition: Transition(transition), - component: AnyComponent(ArchiveInfoContentComponent( - theme: self.theme, - strings: self.strings, - settings: self.globalPrivacySettings, - openSettings: { [weak self] in - guard let self else { - return - } - self.openArchiveSettings() - } - )), - environment: { - }, - containerSize: CGSize(width: size.width, height: size.height - 41.0) - ) - if let emptyArchiveView = emptyArchive.view { - if emptyArchiveView.superview == nil { - self.view.addSubview(emptyArchiveView) - } - transition.updateFrame(view: emptyArchiveView, frame: CGRect(origin: CGPoint(x: floor((size.width - emptyArchiveSize.width) * 0.5), y: 41.0), size: emptyArchiveSize)) - } - } else if let emptyArchive = self.emptyArchive { - self.emptyArchive = nil - emptyArchive.view?.removeFromSuperview() - } + func updateLayout(size: CGSize, insets: UIEdgeInsets, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, insets) let indicatorSize = self.activityIndicator.measure(CGSize(width: 100.0, height: 100.0)) transition.updateFrame(node: self.activityIndicator, frame: CGRect(origin: CGPoint(x: floor((size.width - indicatorSize.width) / 2.0), y: floor((size.height - indicatorSize.height - 50.0) / 2.0)), size: indicatorSize)) @@ -330,6 +300,63 @@ final class ChatListEmptyNode: ASDisplayNode { transition.updateFrame(node: self.buttonNode, frame: buttonFrame) } + func updateScrollingOffset(navigationHeight: CGFloat, offset: CGFloat, transition: ContainedViewLayoutTransition) { + self.scrollingOffset = (navigationHeight, offset) + + guard let (size, _) = self.validLayout else { + return + } + + if case .archive = self.subject { + let emptyArchive: ComponentView + if let current = self.emptyArchive { + emptyArchive = current + } else { + emptyArchive = ComponentView() + self.emptyArchive = emptyArchive + } + let emptyArchiveSize = emptyArchive.update( + transition: Transition(transition), + component: AnyComponent(ArchiveInfoContentComponent( + theme: self.theme, + strings: self.strings, + settings: self.globalPrivacySettings, + openSettings: { [weak self] in + guard let self else { + return + } + self.openArchiveSettings() + } + )), + environment: { + }, + containerSize: CGSize(width: size.width, height: 10000.0) + ) + if let emptyArchiveView = emptyArchive.view { + if emptyArchiveView.superview == nil { + self.view.addSubview(emptyArchiveView) + } + + let cancelledOutHeight: CGFloat = max(0.0, ChatListNavigationBar.searchScrollHeight - offset) + let visibleNavigationHeight: CGFloat = navigationHeight - ChatListNavigationBar.searchScrollHeight + cancelledOutHeight + + let additionalOffset = min(0.0, -offset + ChatListNavigationBar.searchScrollHeight) + + var archiveFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleNavigationHeight + floorToScreenPixels((size.height - visibleNavigationHeight - emptyArchiveSize.height - 50.0) * 0.5)), size: emptyArchiveSize) + archiveFrame.origin.y = max(archiveFrame.origin.y, visibleNavigationHeight + 20.0) + + if size.height - visibleNavigationHeight - emptyArchiveSize.height - 20.0 < 0.0 { + archiveFrame.origin.y += additionalOffset + } + + transition.updateFrame(view: emptyArchiveView, frame: archiveFrame) + } + } else if let emptyArchive = self.emptyArchive { + self.emptyArchive = nil + emptyArchive.view?.removeFromSuperview() + } + } + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if self.buttonNode.frame.contains(point) { return self.buttonNode.view.hitTest(self.view.convert(point, to: self.buttonNode.view), with: event) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index d35456160d..bf851892c7 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -865,7 +865,7 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState, } if displayArchiveIntro { - result.append(.ArchiveIntro(presentationData: state.presentationData)) + //result.append(.ArchiveIntro(presentationData: state.presentationData)) } else if !contacts.isEmpty && !result.contains(where: { entry in if case .PeerEntry = entry { return true diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift index 74e73a0fb2..cf40c49145 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CacheStorageSettings.swift @@ -2,7 +2,7 @@ import Foundation import Postbox public struct CacheStorageSettings: Codable, Equatable { - public enum PeerStorageCategory: String, Codable, Hashable { + public enum PeerStorageCategory: String, Codable, Hashable, CaseIterable { case privateChats = "privateChats" case groups = "groups" case channels = "channels" @@ -61,6 +61,11 @@ public struct CacheStorageSettings: Codable, Equatable { for item in items { categoryStorageTimeout[item.key] = item.value } + for key in PeerStorageCategory.allCases { + if categoryStorageTimeout[key] == nil, let value = CacheStorageSettings.defaultSettings.categoryStorageTimeout[key] { + categoryStorageTimeout[key] = value + } + } self.categoryStorageTimeout = categoryStorageTimeout } else { self.categoryStorageTimeout = CacheStorageSettings.defaultSettings.categoryStorageTimeout diff --git a/submodules/TelegramUI/Components/Settings/ArchiveInfoScreen/Sources/ArchiveInfoContentComponent.swift b/submodules/TelegramUI/Components/Settings/ArchiveInfoScreen/Sources/ArchiveInfoContentComponent.swift index 9c009633e5..0d365fb1ec 100644 --- a/submodules/TelegramUI/Components/Settings/ArchiveInfoScreen/Sources/ArchiveInfoContentComponent.swift +++ b/submodules/TelegramUI/Components/Settings/ArchiveInfoScreen/Sources/ArchiveInfoContentComponent.swift @@ -111,14 +111,14 @@ public final class ArchiveInfoContentComponent: Component { let iconSize: CGFloat = 90.0 if self.iconBackground.image == nil { let backgroundColors = component.theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors - let colors: NSArray = [backgroundColors.0.cgColor, backgroundColors.1.cgColor] + let colors: NSArray = [backgroundColors.1.cgColor, backgroundColors.0.cgColor] self.iconBackground.image = generateGradientFilledCircleImage(diameter: iconSize, colors: colors) } let iconBackgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize) * 0.5), y: contentHeight), size: CGSize(width: iconSize, height: iconSize)) transition.setFrame(view: self.iconBackground, frame: iconBackgroundFrame) if self.iconForeground.image == nil { - self.iconForeground.image = generateTintedImage(image: UIImage(bundleImageName: "Avatar/ArchiveAvatarIcon"), color: .white) + self.iconForeground.image = generateTintedImage(image: UIImage(bundleImageName: "Chat List/ArchiveIconLarge"), color: .white) } if let image = self.iconForeground.image { transition.setFrame(view: self.iconForeground, frame: CGRect(origin: CGPoint(x: iconBackgroundFrame.minX + floor((iconBackgroundFrame.width - image.size.width) * 0.5), y: iconBackgroundFrame.minY + floor((iconBackgroundFrame.height - image.size.height) * 0.5)), size: image.size)) diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Contents.json new file mode 100644 index 0000000000..1a138e2a65 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Union.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Union.svg b/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Union.svg new file mode 100644 index 0000000000..9010919106 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat List/ArchiveIconLarge.imageset/Union.svg @@ -0,0 +1,3 @@ + + +