diff --git a/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@2x.png b/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@2x.png index 891ff5729e..05f1d6839e 100644 Binary files a/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@2x.png and b/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@2x.png differ diff --git a/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@3x.png b/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@3x.png index 6a83bd6850..1f53405b9c 100644 Binary files a/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@3x.png and b/Images.xcassets/Avatar/ArchiveAvatarIcon.imageset/ArchiveAvatar@3x.png differ diff --git a/TelegramUI/AvatarNode.swift b/TelegramUI/AvatarNode.swift index 387c4ab782..b919969cf2 100644 --- a/TelegramUI/AvatarNode.swift +++ b/TelegramUI/AvatarNode.swift @@ -227,7 +227,7 @@ public final class AvatarNode: ASDisplayNode { representation = peer?.smallProfileImage } let updatedState: AvatarNodeState = .peerAvatar(peer?.id ?? PeerId(namespace: 0, id: 0), peer?.displayLetters ?? [], representation) - if updatedState != self.state { + if updatedState != self.state || theme !== self.theme { self.state = updatedState let parameters: AvatarNodeParameters diff --git a/TelegramUI/ChatHistoryListNode.swift b/TelegramUI/ChatHistoryListNode.swift index d3c1b20c89..96fe9adb85 100644 --- a/TelegramUI/ChatHistoryListNode.swift +++ b/TelegramUI/ChatHistoryListNode.swift @@ -293,6 +293,19 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist return associatedData } +private extension ChatHistoryLocationInput { + var isAtUpperBound: Bool { + switch self.content { + case .Navigation(index: .upperBound, anchorIndex: .upperBound, count: _): + return true + case .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: _, scrollPosition: _, animated: _): + return true + default: + return false + } + } +} + public final class ChatHistoryListNode: ListView, ChatHistoryNode { private let context: AccountContext private let chatLocation: ChatLocation @@ -337,7 +350,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { private var canReadHistoryValue: Bool = false private var canReadHistoryDisposable: Disposable? - private let chatHistoryLocation = ValuePromise() + private var chatHistoryLocationValue: ChatHistoryLocationInput? { + didSet { + if let chatHistoryLocationValue = self.chatHistoryLocationValue, chatHistoryLocationValue != oldValue { + chatHistoryLocationPromise.set(chatHistoryLocationValue) + } + } + } + private let chatHistoryLocationPromise = ValuePromise() private var nextHistoryLocationId: Int32 = 1 private func takeNextHistoryLocationId() -> Int32 { let id = self.nextHistoryLocationId @@ -455,7 +475,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } additionalData.append(.totalUnreadState) - let historyViewUpdate = self.chatHistoryLocation.get() + let historyViewUpdate = self.chatHistoryLocationPromise.get() |> distinctUntilChanged |> mapToSignal { location in return chatHistoryViewForLocation(location, account: context.account, chatLocation: chatLocation, fixedCombinedReadStates: fixedCombinedReadStates.with { $0 }, tagMask: tagMask, additionalData: additionalData) @@ -494,12 +514,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if let filteredEntries = historyView?.filteredEntries, let visibleRange = displayRange.visibleRange { let lastEntry = filteredEntries[filteredEntries.count - 1 - visibleRange.lastIndex] - strongSelf.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: 0)) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: 0) } else { if let messageId = messageId { - strongSelf.chatHistoryLocation.set(ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0)) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0) } else { - strongSelf.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Initial(count: 60), id: 0)) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Initial(count: 60), id: 0) } } } @@ -670,10 +690,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { }) if let messageId = messageId { - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0)) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0) } else { - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Initial(count: 60), id: 0)) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Initial(count: 60), id: 0) } + self.chatHistoryLocationPromise.set(self.chatHistoryLocationValue!) self.generalScrollDirectionUpdated = { [weak self] direction in guard let strongSelf = self else { @@ -862,9 +883,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if let loaded = displayedRange.loadedRange, let firstEntry = historyView.filteredEntries.first, let lastEntry = historyView.filteredEntries.last { if loaded.firstIndex < 5 && historyView.originalView.laterId != nil { - strongSelf.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: 0)) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: 0) + } else if loaded.firstIndex < 5, historyView.originalView.laterId == nil, !historyView.originalView.holeLater, let chatHistoryLocationValue = strongSelf.chatHistoryLocationValue, !chatHistoryLocationValue.isAtUpperBound, historyView.originalView.anchorIndex != .upperBound { + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .upperBound, anchorIndex: .upperBound, count: historyMessageCount), id: 0) } else if loaded.lastIndex >= historyView.filteredEntries.count - 5 && historyView.originalView.earlierId != nil { - strongSelf.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount), id: 0)) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount), id: 0) } } @@ -992,12 +1015,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } if let currentMessage = currentMessage { - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Scroll(index: .message(currentMessage.index), anchorIndex: .message(currentMessage.index), sourceIndex: .upperBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId())) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(currentMessage.index), anchorIndex: .message(currentMessage.index), sourceIndex: .upperBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId()) } } public func scrollToStartOfHistory() { - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: self.takeNextHistoryLocationId())) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: self.takeNextHistoryLocationId()) } public func scrollToEndOfHistory() { @@ -1005,12 +1028,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { case .known(0.0): break default: - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId())) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId()) } } public func scrollToMessage(from fromIndex: MessageIndex, to toIndex: MessageIndex, animated: Bool, highlight: Bool = true, scrollPosition: ListViewScrollPosition = .center(.bottom)) { - self.chatHistoryLocation.set(ChatHistoryLocationInput(content: .Scroll(index: .message(toIndex), anchorIndex: .message(toIndex), sourceIndex: .message(fromIndex), scrollPosition: scrollPosition, animated: animated), id: self.takeNextHistoryLocationId())) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(toIndex), anchorIndex: .message(toIndex), sourceIndex: .message(fromIndex), scrollPosition: scrollPosition, animated: animated), id: self.takeNextHistoryLocationId()) } func scrollWithDeltaOffset(_ offset: CGFloat) { diff --git a/TelegramUI/ItemListRevealOptionsNode.swift b/TelegramUI/ItemListRevealOptionsNode.swift index 0cfa4293a8..f3d61a03a1 100644 --- a/TelegramUI/ItemListRevealOptionsNode.swift +++ b/TelegramUI/ItemListRevealOptionsNode.swift @@ -224,15 +224,19 @@ private final class ItemListRevealOptionNode: ASDisplayNode { let titleIconSpacing: CGFloat = 11.0 let iconFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - imageSize.width + sideInset) / 2.0), y: contentRect.midY - imageSize.height / 2.0 + iconOffset), size: imageSize) if animateAdditive { + animationNode.frame = iconFrame transition.animatePositionAdditive(node: animationNode, offset: CGPoint(x: deltaX, y: 0.0)) + } else { + transition.updateFrame(node: animationNode, frame: iconFrame) } - animationNode.frame = iconFrame let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - titleSize.width + sideInset) / 2.0), y: contentRect.midY + titleIconSpacing), size: titleSize) if animateAdditive { + self.titleNode.frame = titleFrame transition.animatePositionAdditive(node: self.titleNode, offset: CGPoint(x: deltaX, y: 0.0)) + } else { + transition.updateFrame(node: self.titleNode, frame: titleFrame) } - self.titleNode.frame = titleFrame if (abs(revealFactor) >= 0.4) { animationNode.play() @@ -244,17 +248,27 @@ private final class ItemListRevealOptionNode: ASDisplayNode { let titleIconSpacing: CGFloat = 11.0 let iconFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - imageSize.width + sideInset) / 2.0), y: contentRect.midY - imageSize.height / 2.0 + iconOffset), size: imageSize) if animateAdditive { + iconNode.frame = iconFrame transition.animatePositionAdditive(node: iconNode, offset: CGPoint(x: deltaX, y: 0.0)) + } else { + transition.updateFrame(node: iconNode, frame: iconFrame) } - iconNode.frame = iconFrame let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - titleSize.width + sideInset) / 2.0), y: contentRect.midY + titleIconSpacing), size: titleSize) if animateAdditive { + self.titleNode.frame = titleFrame transition.animatePositionAdditive(node: self.titleNode, offset: CGPoint(x: deltaX, y: 0.0)) + } else { + transition.updateFrame(node: self.titleNode, frame: titleFrame) } - self.titleNode.frame = titleFrame } else { - self.titleNode.frame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - titleSize.width + sideInset) / 2.0), y: contentRect.minY + floor((baseSize.height - titleSize.height) / 2.0)), size: titleSize) + let titleFrame = CGRect(origin: CGPoint(x: contentRect.minX + floor((baseSize.width - titleSize.width + sideInset) / 2.0), y: contentRect.minY + floor((baseSize.height - titleSize.height) / 2.0)), size: titleSize) + if animateAdditive { + self.titleNode.frame = titleFrame + transition.animatePositionAdditive(node: self.titleNode, offset: CGPoint(x: deltaX, y: 0.0)) + } else { + transition.updateFrame(node: self.titleNode, frame: titleFrame) + } } } @@ -296,7 +310,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode { } for node in strongSelf.optionNodes { if node.frame.contains(location) { - node.setHighlighted(true) + //node.setHighlighted(true) break } } @@ -350,28 +364,25 @@ final class ItemListRevealOptionsNode: ASDisplayNode { if size.width.isLessThanOrEqualTo(0.0) || self.optionNodes.isEmpty { return } - let basicNodeWidth = floorToScreenPixels((size.width - abs(self.sideInset)) / CGFloat(self.optionNodes.count)) + let basicNodeWidth = floor((size.width - abs(self.sideInset)) / CGFloat(self.optionNodes.count)) let lastNodeWidth = size.width - basicNodeWidth * CGFloat(self.optionNodes.count - 1) let revealFactor = self.revealOffset / size.width - let boundaryRevealFactor: CGFloat = 1.0 + basicNodeWidth / size.width * 0.7 - var leftOffset: CGFloat + let boundaryRevealFactor: CGFloat = 1.0 + 16.0 / size.width + let startingOffset: CGFloat if self.isLeft { - leftOffset = size.width + max(0.0, abs(revealFactor) - 1.0) * size.width + startingOffset = size.width + max(0.0, abs(revealFactor) - 1.0) * size.width } else { - leftOffset = 0.0 + startingOffset = 0.0 } var i = self.isLeft ? (self.optionNodes.count - 1) : 0 while i >= 0 && i < self.optionNodes.count { let node = self.optionNodes[i] let nodeWidth = i == (self.optionNodes.count - 1) ? lastNodeWidth : basicNodeWidth - var extendedWidth = nodeWidth let defaultAlignment: ItemListRevealOptionAlignment = isLeft ? .right : .left var nodeTransition = transition - extendedWidth = floorToScreenPixels(nodeWidth * max(1.0, abs(revealFactor))) var isExpanded = false if (isLeft && i == 0) || (!isLeft && i == self.optionNodes.count - 1) { if abs(revealFactor) > boundaryRevealFactor { - extendedWidth = size.width * max(1.0, abs(revealFactor)) isExpanded = true } } @@ -387,31 +398,34 @@ final class ItemListRevealOptionsNode: ASDisplayNode { sideInset = self.sideInset } - var nodeLeftOffset = leftOffset - if self.isLeft { - nodeLeftOffset -= extendedWidth - } else { - nodeLeftOffset *= abs(revealFactor) - } + let extendedWidth: CGFloat + let nodeLeftOffset: CGFloat if isExpanded { nodeLeftOffset = 0.0 + extendedWidth = size.width * max(1.0, abs(revealFactor)) + } else if self.isLeft { + let offset = basicNodeWidth * CGFloat(self.optionNodes.count - 1 - i) + extendedWidth = size.width - offset + nodeLeftOffset = startingOffset - extendedWidth - floorToScreenPixels(offset * abs(revealFactor)) + } else { + let offset = basicNodeWidth * CGFloat(i) + extendedWidth = size.width - offset + nodeLeftOffset = startingOffset + floorToScreenPixels(offset * abs(revealFactor)) } - transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: floorToScreenPixels(nodeLeftOffset), y: 0.0), size: CGSize(width: extendedWidth, height: size.height))) + transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: nodeLeftOffset, y: 0.0), size: CGSize(width: extendedWidth, height: size.height))) node.updateLayout(isFirst: (self.isLeft && i == 0) || (!self.isLeft && i == self.optionNodes.count - 1), isLeft: self.isLeft, baseSize: CGSize(width: nodeWidth, height: size.height), alignment: defaultAlignment, isExpanded: isExpanded, extendedWidth: extendedWidth, sideInset: sideInset, transition: nodeTransition, additive: !transition.isAnimated, revealFactor: revealFactor) if self.isLeft { - leftOffset -= extendedWidth i -= 1 } else { - leftOffset += nodeWidth i += 1 } } } @objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { - if case .ended = recognizer.state { + if case .ended = recognizer.state, let gesture = recognizer.lastRecognizedGestureAndLocation?.0, case .tap = gesture { let location = recognizer.location(in: self.view) var selectedOption: Int? for i in 0 ..< self.optionNodes.count { diff --git a/TelegramUI/ManagedAudioSession.swift b/TelegramUI/ManagedAudioSession.swift index 3c4957287e..c33546de36 100644 --- a/TelegramUI/ManagedAudioSession.swift +++ b/TelegramUI/ManagedAudioSession.swift @@ -644,7 +644,7 @@ public final class ManagedAudioSession { case .record, .voiceCall: options.insert(.allowBluetooth) } - print("ManagedAudioSession setting active \(type != .none)") + print("ManagedAudioSession setting active true") if #available(iOSApplicationExtension 11.0, *) { try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), mode: type == .voiceCall ? AVAudioSessionModeVoiceChat : AVAudioSessionModeDefault, routeSharingPolicy: .default, options: options) } else {