Peer info bug fixes

This commit is contained in:
Ali 2020-02-16 00:52:07 +01:00
parent 9fba3f208a
commit 14e007b236
31 changed files with 4411 additions and 3933 deletions

View File

@ -5330,6 +5330,7 @@ Any member of this group will be able to see messages in the channel.";
"PeerInfo.ButtonUnmute" = "Unmute";
"PeerInfo.ButtonMore" = "More";
"PeerInfo.ButtonAddMember" = "Add Members";
"PeerInfo.ButtonSearch" = "Search";
"PeerInfo.PaneMedia" = "Media";
"PeerInfo.PaneFiles" = "Files";
@ -5340,3 +5341,5 @@ Any member of this group will be able to see messages in the channel.";
"PeerInfo.PaneMembers" = "Members";
"PeerInfo.AddToContacts" = "Add to Contacts";
"PeerInfo.BioExpand" = "more";

View File

@ -16,6 +16,8 @@ public final class ContextControllerSourceNode: ASDisplayNode {
public func cancelGesture() {
self.contextGesture?.cancel()
self.contextGesture?.isEnabled = false
self.contextGesture?.isEnabled = self.isGestureEnabled
}
override public func didLoad() {

View File

@ -31,16 +31,26 @@ private func hasHorizontalGestures(_ view: UIView, point: CGPoint?) -> Bool {
}
}
public struct InteractiveTransitionGestureRecognizerDirections: OptionSet {
public var rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
public static let left = InteractiveTransitionGestureRecognizerDirections(rawValue: 1 << 0)
public static let right = InteractiveTransitionGestureRecognizerDirections(rawValue: 1 << 1)
}
public class InteractiveTransitionGestureRecognizer: UIPanGestureRecognizer {
private let enableBothDirections: Bool
private let canBegin: () -> Bool
private let allowedDirections: () -> InteractiveTransitionGestureRecognizerDirections
var validatedGesture = false
var firstLocation: CGPoint = CGPoint()
private var validatedGesture = false
private var firstLocation: CGPoint = CGPoint()
private var currentAllowedDirections: InteractiveTransitionGestureRecognizerDirections = []
public init(target: Any?, action: Selector?, enableBothDirections: Bool = false, canBegin: @escaping () -> Bool) {
self.enableBothDirections = enableBothDirections
self.canBegin = canBegin
public init(target: Any?, action: Selector?, allowedDirections: @escaping () -> InteractiveTransitionGestureRecognizerDirections) {
self.allowedDirections = allowedDirections
super.init(target: target, action: action)
@ -50,11 +60,13 @@ public class InteractiveTransitionGestureRecognizer: UIPanGestureRecognizer {
override public func reset() {
super.reset()
validatedGesture = false
self.validatedGesture = false
self.currentAllowedDirections = []
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if !self.canBegin() {
self.currentAllowedDirections = self.allowedDirections()
if self.currentAllowedDirections.isEmpty {
self.state = .failed
return
}
@ -79,14 +91,16 @@ public class InteractiveTransitionGestureRecognizer: UIPanGestureRecognizer {
let absTranslationY: CGFloat = abs(translation.y)
if !self.validatedGesture {
if !self.enableBothDirections && self.firstLocation.x < 16.0 {
validatedGesture = true
} else if !self.enableBothDirections && translation.x < 0.0 {
if self.currentAllowedDirections.contains(.left) && self.firstLocation.x < 16.0 {
self.validatedGesture = true
} else if !self.currentAllowedDirections.contains(.left) && translation.x < 0.0 {
self.state = .failed
} else if !self.currentAllowedDirections.contains(.right) && translation.x > 0.0 {
self.state = .failed
} else if absTranslationY > 2.0 && absTranslationY > absTranslationX * 2.0 {
self.state = .failed
} else if absTranslationX > 2.0 && absTranslationY * 2.0 < absTranslationX {
validatedGesture = true
self.validatedGesture = true
}
}

View File

@ -111,11 +111,11 @@ final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelegate {
override func didLoad() {
super.didLoad()
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), canBegin: { [weak self] in
guard let strongSelf = self else {
return false
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] in
guard let strongSelf = self, strongSelf.controllers.count > 1 else {
return []
}
return strongSelf.controllers.count > 1
return .right
})
panRecognizer.delegate = self
panRecognizer.delaysTouchesBegan = false

View File

@ -90,11 +90,11 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
self.scrollNode.view.clipsToBounds = false
self.scrollNode.view.delegate = self
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), canBegin: { [weak self] in
guard let strongSelf = self else {
return false
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] in
guard let strongSelf = self, !strongSelf.isDismissed else {
return []
}
return !strongSelf.isDismissed
return .right
})
self.panRecognizer = panRecognizer
if let layout = self.validLayout {

View File

@ -227,6 +227,8 @@ static NSString *makeRandomPadding() {
+ (MTSignal *)fetchConfigFromAddress:(MTBackupDatacenterAddress *)address currentContext:(MTContext *)currentContext {
MTApiEnvironment *apiEnvironment = [currentContext.apiEnvironment copy];
apiEnvironment = [apiEnvironment withUpdatedSocksProxySettings:nil];
NSMutableDictionary *datacenterAddressOverrides = [[NSMutableDictionary alloc] init];
datacenterAddressOverrides[@(address.datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false secret:address.secret];

View File

@ -8,7 +8,7 @@ import Postbox
import TelegramPresentationData
import AccountContext
final class SecretChatKeyController: ViewController {
public final class SecretChatKeyController: ViewController {
private var controllerNode: SecretChatKeyControllerNode {
return self.displayNode as! SecretChatKeyControllerNode
}
@ -19,7 +19,7 @@ final class SecretChatKeyController: ViewController {
private var presentationData: PresentationData
init(context: AccountContext, fingerprint: SecretChatKeyFingerprint, peer: Peer) {
public init(context: AccountContext, fingerprint: SecretChatKeyFingerprint, peer: Peer) {
self.context = context
self.fingerprint = fingerprint
self.peer = peer
@ -34,11 +34,11 @@ final class SecretChatKeyController: ViewController {
self.title = self.presentationData.strings.EncryptionKey_Title
}
required init(coder aDecoder: NSCoder) {
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadDisplayNode() {
override public func loadDisplayNode() {
self.displayNode = SecretChatKeyControllerNode(context: self.context, presentationData: self.presentationData, fingerprint: self.fingerprint, peer: self.peer, getNavigationController: { [weak self] in
return self?.navigationController as? NavigationController
})

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_search.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -305,7 +305,7 @@ public final class ChatHistoryGridNode: GridNode, ChatHistoryNode {
}
let associatedData = ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: false)
let processedView = ChatHistoryView(originalView: view, filteredEntries: chatHistoryEntriesForView(location: .peer(peerId), view: view, includeUnreadEntry: false, includeEmptyEntry: false, includeChatInfoEntry: false, includeSearchEntry: false, reverse: false, groupMessages: false, selectedMessages: nil, presentationData: chatPresentationData, historyAppearsCleared: false, associatedData: associatedData, updatingMedia: [:]), associatedData: associatedData, id: id)
let processedView = ChatHistoryView(originalView: view, filteredEntries: chatHistoryEntriesForView(location: .peer(peerId), view: view, includeUnreadEntry: false, includeEmptyEntry: false, includeChatInfoEntry: false, includeSearchEntry: false, reverse: false, groupMessages: false, selectedMessages: nil, presentationData: chatPresentationData, historyAppearsCleared: false, associatedData: associatedData, updatingMedia: [:]), associatedData: associatedData, lastHeaderId: 0, id: id)
let previous = previousView.swap(processedView)
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: false, chatLocation: .peer(peerId), controllerInteraction: controllerInteraction, scrollPosition: scrollPosition, initialData: nil, keyboardButtonsMessage: nil, cachedData: nil, cachedDataMessages: nil, readStateData: nil, flashIndicators: flashIndicators, updatedMessageSelection: false)

View File

@ -66,26 +66,15 @@ private class ChatHistoryListSelectionRecognizer: UIPanGestureRecognizer {
private let historyMessageCount: Int = 90
public enum ChatHistoryListDisplayHeaders {
case none
case all
case allButLast
}
public enum ChatHistoryListMode: Equatable {
case bubbles
case list(search: Bool, reversed: Bool)
public static func ==(lhs: ChatHistoryListMode, rhs: ChatHistoryListMode) -> Bool {
switch lhs {
case .bubbles:
if case .bubbles = rhs {
return true
} else {
return false
}
case let .list(search, reversed):
if case .list(search, reversed) = rhs {
return true
} else {
return false
}
}
}
case list(search: Bool, reversed: Bool, displayHeaders: ChatHistoryListDisplayHeaders)
}
enum ChatHistoryViewScrollPosition {
@ -122,6 +111,7 @@ struct ChatHistoryView {
let originalView: MessageHistoryView
let filteredEntries: [ChatHistoryEntry]
let associatedData: ChatMessageItemAssociatedData
let lastHeaderId: Int64
let id: Int32
}
@ -229,7 +219,7 @@ private func maxMessageIndexForEntries(_ view: ChatHistoryView, indexRange: (Int
return (incoming, overall)
}
private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] {
private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] {
return entries.map { entry -> ListViewInsertItem in
switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
@ -237,8 +227,18 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
case let .list(_, _, displayHeaders):
let displayHeader: Bool
switch displayHeaders {
case .none:
displayHeader = false
case .all:
displayHeader = true
case .allButLast:
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
}
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: displayHeader)
}
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .MessageGroupEntry(_, messages, presentationData):
@ -246,9 +246,9 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
case let .list(search, _):
case let .list(_, _, _):
assertionFailure()
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search)
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: false)
}
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData):
@ -263,7 +263,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
}
}
private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
return entries.map { entry -> ListViewUpdateItem in
switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
@ -271,8 +271,17 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
case let .list(_, _, displayHeaders):
let displayHeader: Bool
switch displayHeaders {
case .none:
displayHeader = false
case .all:
displayHeader = true
case .allButLast:
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId
}
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: displayHeader)
}
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .MessageGroupEntry(_, messages, presentationData):
@ -280,9 +289,9 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .group(messages: messages))
case let .list(search, _):
case let .list(_, _, _):
assertionFailure()
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: search)
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: messages[0].0, selection: .none, displayHeader: false)
}
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
case let .UnreadEntry(_, presentationData):
@ -297,8 +306,8 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
}
}
private func mappedChatHistoryViewListTransition(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, transition: ChatHistoryViewTransition) -> ChatHistoryListViewTransition {
return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, animateIn: transition.animateIn, reason: transition.reason, flashIndicators: transition.flashIndicators)
private func mappedChatHistoryViewListTransition(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, transition: ChatHistoryViewTransition) -> ChatHistoryListViewTransition {
return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, animateIn: transition.animateIn, reason: transition.reason, flashIndicators: transition.flashIndicators)
}
private final class ChatHistoryTransactionOpaqueState {
@ -731,7 +740,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
var reverse = false
var includeSearchEntry = false
if case let .list(search, reverseValue) = mode {
if case let .list(search, reverseValue, _) = mode {
includeSearchEntry = search
reverse = reverseValue
}
@ -743,7 +752,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, isScheduledMessages: isScheduledMessages)
let processedView = ChatHistoryView(originalView: view, filteredEntries: chatHistoryEntriesForView(location: chatLocation, view: view, includeUnreadEntry: mode == .bubbles, includeEmptyEntry: mode == .bubbles && tagMask == nil, includeChatInfoEntry: mode == .bubbles, includeSearchEntry: includeSearchEntry && tagMask != nil, reverse: reverse, groupMessages: mode == .bubbles, selectedMessages: selectedMessages, presentationData: chatPresentationData, historyAppearsCleared: historyAppearsCleared, associatedData: associatedData, updatingMedia: updatingMedia), associatedData: associatedData, id: id)
let filteredEntries = chatHistoryEntriesForView(location: chatLocation, view: view, includeUnreadEntry: mode == .bubbles, includeEmptyEntry: mode == .bubbles && tagMask == nil, includeChatInfoEntry: mode == .bubbles, includeSearchEntry: includeSearchEntry && tagMask != nil, reverse: reverse, groupMessages: mode == .bubbles, selectedMessages: selectedMessages, presentationData: chatPresentationData, historyAppearsCleared: historyAppearsCleared, associatedData: associatedData, updatingMedia: updatingMedia)
let lastHeaderId = filteredEntries.last.flatMap { listMessageDateHeaderId(timestamp: $0.index.timestamp) } ?? 0
let processedView = ChatHistoryView(originalView: view, filteredEntries: filteredEntries, associatedData: associatedData, lastHeaderId: lastHeaderId, id: id)
let previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages))
let previous = previousValueAndVersion?.0
let previousSelectedMessages = previousValueAndVersion?.2
@ -794,7 +805,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
}
}
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages)
let mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, transition: rawTransition)
let mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, transition: rawTransition)
Queue.mainQueue().async {
guard let strongSelf = self else {
return
@ -1670,8 +1681,17 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
switch self.mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: self.context, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: search)
case let .list(_, _, displayHeaders):
let displayHeader: Bool
switch displayHeaders {
case .none:
displayHeader = false
case .all:
displayHeader = true
case .allButLast:
displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != historyView.lastHeaderId
}
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, fontSize: presentationData.fontSize, dateTimeFormat: presentationData.dateTimeFormat, context: self.context, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: displayHeader)
}
let updateItem = ListViewUpdateItem(index: index, previousIndex: index, item: item, directionHint: nil)
self.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [updateItem], options: [.AnimateInsertion], scrollToItem: nil, additionalScrollDistance: 0.0, updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })

View File

@ -73,7 +73,7 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
}
if presentationInterfaceState.isScheduledMessages {
return nil
return chatInfoNavigationButton
}
if case .standard(true) = presentationInterfaceState.mode {

View File

@ -2311,7 +2311,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame)
} else {
if item.message.id.peerId == item.context.account.peerId, let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil {
if case .member = channel.participationStatus {
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
} else if case .member = channel.participationStatus {
} else {
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
return true

View File

@ -14,6 +14,24 @@ private let timezoneOffset: Int32 = {
return Int32(timeinfoNow.tm_gmtoff)
}()
func listMessageDateHeaderId(timestamp: Int32) -> Int64 {
var time: time_t = time_t(timestamp + timezoneOffset)
var timeinfo: tm = tm()
localtime_r(&time, &timeinfo)
let roundedTimestamp = timeinfo.tm_year * 100 + timeinfo.tm_mon
return Int64(roundedTimestamp)
}
func listMessageDateHeaderInfo(timestamp: Int32) -> (year: Int32, month: Int32) {
var time: time_t = time_t(timestamp + timezoneOffset)
var timeinfo: tm = tm()
localtime_r(&time, &timeinfo)
return (timeinfo.tm_year, timeinfo.tm_mon)
}
final class ListMessageDateHeader: ListViewItemHeader {
private let timestamp: Int32
private let roundedTimestamp: Int32

View File

@ -150,7 +150,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
tagMask = .voiceOrInstantVideo
}
self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: .message(initialMessageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: currentIsReversed))
self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: .message(initialMessageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: currentIsReversed, displayHeaders: .none))
super.init()
@ -480,7 +480,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
tagMask = .voiceOrInstantVideo
}
let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), tagMask: tagMask, subject: .message(messageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed))
let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), tagMask: tagMask, subject: .message(messageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none))
historyNode.preloadPages = true
historyNode.stackFromBottom = true
historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in

View File

@ -0,0 +1,118 @@
import AsyncDisplayKit
import Display
import TelegramPresentationData
import SyncCore
import EncryptionKeyVisualization
final class PeerInfoScreenDisclosureEncryptionKeyItem: PeerInfoScreenItem {
let id: AnyHashable
let text: String
let fingerprint: SecretChatKeyFingerprint
let action: (() -> Void)?
init(id: AnyHashable, text: String, fingerprint: SecretChatKeyFingerprint, action: (() -> Void)?) {
self.id = id
self.text = text
self.fingerprint = fingerprint
self.action = action
}
func node() -> PeerInfoScreenItemNode {
return PeerInfoScreenDisclosureEncryptionKeyItemNode()
}
}
private final class PeerInfoScreenDisclosureEncryptionKeyItemNode: PeerInfoScreenItemNode {
private let selectionNode: PeerInfoScreenSelectableBackgroundNode
private let textNode: ImmediateTextNode
private let keyNode: ASImageNode
private let arrowNode: ASImageNode
private let bottomSeparatorNode: ASDisplayNode
private var item: PeerInfoScreenDisclosureEncryptionKeyItem?
override init() {
var bringToFrontForHighlightImpl: (() -> Void)?
self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() })
self.textNode = ImmediateTextNode()
self.textNode.displaysAsynchronously = false
self.textNode.isUserInteractionEnabled = false
self.keyNode = ASImageNode()
self.keyNode.displaysAsynchronously = false
self.keyNode.displayWithoutProcessing = true
self.keyNode.isUserInteractionEnabled = false
self.arrowNode = ASImageNode()
self.arrowNode.isLayerBacked = true
self.arrowNode.displaysAsynchronously = false
self.arrowNode.displayWithoutProcessing = true
self.arrowNode.isUserInteractionEnabled = false
self.bottomSeparatorNode = ASDisplayNode()
self.bottomSeparatorNode.isLayerBacked = true
super.init()
bringToFrontForHighlightImpl = { [weak self] in
self?.bringToFrontForHighlight?()
}
self.addSubnode(self.bottomSeparatorNode)
self.addSubnode(self.selectionNode)
self.addSubnode(self.textNode)
self.addSubnode(self.keyNode)
self.addSubnode(self.arrowNode)
}
override func update(width: CGFloat, presentationData: PresentationData, item: PeerInfoScreenItem, topItem: PeerInfoScreenItem?, bottomItem: PeerInfoScreenItem?, transition: ContainedViewLayoutTransition) -> CGFloat {
guard let item = item as? PeerInfoScreenDisclosureEncryptionKeyItem else {
return 10.0
}
if self.item?.fingerprint != item.fingerprint {
self.keyNode.image = secretChatKeyImage(item.fingerprint, size: CGSize(width: 24.0, height: 24.0))
}
self.item = item
self.selectionNode.pressed = item.action
let sideInset: CGFloat = 16.0
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
self.textNode.maximumNumberOfLines = 1
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0 - 44.0, height: .greatestFiniteMagnitude))
let arrowInset: CGFloat = 18.0
let textFrame = CGRect(origin: CGPoint(x: sideInset, y: 11.0), size: textSize)
let height = textSize.height + 22.0
if let arrowImage = PresentationResourcesItemList.disclosureArrowImage(presentationData.theme) {
self.arrowNode.image = arrowImage
let arrowFrame = CGRect(origin: CGPoint(x: width - 7.0 - arrowImage.size.width, y: floorToScreenPixels((height - arrowImage.size.height) / 2.0)), size: arrowImage.size)
transition.updateFrame(node: self.arrowNode, frame: arrowFrame)
}
if let image = self.keyNode.image {
self.keyNode.frame = CGRect(origin: CGPoint(x: width - sideInset - arrowInset - image.size.width, y: floor((height - image.size.height) / 2.0)), size: image.size)
}
transition.updateFrame(node: self.textNode, frame: textFrame)
let highlightNodeOffset: CGFloat = topItem == nil ? 0.0 : UIScreenPixel
self.selectionNode.update(size: CGSize(width: width, height: height + highlightNodeOffset), theme: presentationData.theme, transition: transition)
transition.updateFrame(node: self.selectionNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -highlightNodeOffset), size: CGSize(width: width, height: height + highlightNodeOffset)))
transition.updateFrame(node: self.bottomSeparatorNode, frame: CGRect(origin: CGPoint(x: sideInset, y: height - UIScreenPixel), size: CGSize(width: width - sideInset, height: UIScreenPixel)))
transition.updateAlpha(node: self.bottomSeparatorNode, alpha: bottomItem == nil ? 0.0 : 1.0)
return height
}
}

View File

@ -200,7 +200,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
textColorValue = presentationData.theme.list.itemAccentColor
}
self.expandNode.attributedText = NSAttributedString(string: "more", font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor)
self.expandNode.attributedText = NSAttributedString(string: presentationData.strings.PeerInfo_BioExpand, font: Font.regular(17.0), textColor: presentationData.theme.list.itemAccentColor)
let expandSize = self.expandNode.updateLayout(CGSize(width: width, height: 100.0))
self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(14.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
@ -211,7 +211,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.textNode.maximumNumberOfLines = 1
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
case let .multiLine(maxLines, enabledEntities):
self.textNode.maximumNumberOfLines = self.isExpanded ? maxLines : 2
self.textNode.maximumNumberOfLines = self.isExpanded ? maxLines : 3
self.textNode.cutout = self.isExpanded ? nil : TextNodeCutout(bottomRight: CGSize(width: expandSize.width + 4.0, height: expandSize.height))
if enabledEntities.isEmpty {
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)

View File

@ -204,6 +204,9 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
}
func cancelPreviewGestures() {
}
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
return nil
}

View File

@ -44,7 +44,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
self.selectedMessagesPromise.set(.single(self.selectedMessages))
self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false))
self.listNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast))
super.init()
@ -106,6 +106,9 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
}
func cancelPreviewGestures() {
}
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
self.listNode.forEachItemNode { itemNode in

View File

@ -247,6 +247,9 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
}
func cancelPreviewGestures() {
}
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
return nil
}

View File

@ -92,6 +92,10 @@ private final class VisualMediaItemNode: ASDisplayNode {
return .waitForSingleTap
}
self.imageNode.view.addGestureRecognizer(recognizer)
self.mediaBadgeNode.pressed = { [weak self] in
self?.progressPressed()
}
}
@objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
@ -99,13 +103,62 @@ private final class VisualMediaItemNode: ASDisplayNode {
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
if case .tap = gesture {
if let (item, _, _, _) = self.item {
self.interaction.openMessage(item.message)
var media: Media?
for value in item.message.media {
if let image = value as? TelegramMediaImage {
media = image
break
} else if let file = value as? TelegramMediaFile {
media = file
break
}
}
if let media = media {
if let file = media as? TelegramMediaFile {
if isMediaStreamable(message: item.message, media: file) {
self.interaction.openMessage(item.message)
} else {
self.progressPressed()
}
} else {
self.interaction.openMessage(item.message)
}
}
}
}
}
}
}
private func progressPressed() {
guard let message = self.item?.0.message else {
return
}
var media: Media?
for value in message.media {
if let image = value as? TelegramMediaImage {
media = image
break
} else if let file = value as? TelegramMediaFile {
media = file
break
}
}
if let resourceStatus = self.resourceStatus, let file = media as? TelegramMediaFile {
switch resourceStatus {
case .Fetching:
messageMediaFileCancelInteractiveFetch(context: self.context, messageId: message.id, file: file)
case .Local:
self.interaction.openMessage(message)
case .Remote:
self.fetchDisposable.set(messageMediaFileInteractiveFetched(context: self.context, message: message, file: file, userInitiated: true).start())
}
}
}
func cancelPreviewGesture() {
self.containerNode.cancelGesture()
}
@ -146,32 +199,36 @@ private final class VisualMediaItemNode: ASDisplayNode {
self.mediaBadgeNode.isHidden = false
self.resourceStatus = nil
self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: item.message.id, file: file) |> deliverOnMainQueue).start(next: { [weak self] status in
self.item = (item, media, size, mediaDimensions)
self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: item.message.id, file: file)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self, let (item, _, _, _) = strongSelf.item {
strongSelf.resourceStatus = status
let isStreamable = isMediaStreamable(message: item.message, media: file)
let statusState: RadialStatusNodeState = .none
/*if isStreamable {
var statusState: RadialStatusNodeState = .none
if isStreamable {
statusState = .none
} else {
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
case .Local:
statusState = .none
case .Remote:
statusState = .download(.white)
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
statusState = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
case .Local:
statusState = .none
case .Remote:
statusState = .download(.white)
}
}*/
}
switch statusState {
case .none:
break
default:
strongSelf.statusNode.isHidden = false
case .none:
break
default:
strongSelf.statusNode.isHidden = false
}
strongSelf.statusNode.transitionToState(statusState, animated: true, completion: {
@ -328,12 +385,64 @@ private final class VisualMediaItem {
}
}
private final class FloatingHeaderNode: ASDisplayNode {
private let backgroundNode: ASImageNode
private let labelNode: ImmediateTextNode
private var currentParams: (constrainedWidth: CGFloat, year: Int32, month: Int32, theme: PresentationTheme)?
private var currentSize: CGSize?
override init() {
self.backgroundNode = ASImageNode()
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.labelNode = ImmediateTextNode()
self.labelNode.displaysAsynchronously = false
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.labelNode)
}
func update(constrainedWidth: CGFloat, year: Int32, month: Int32, theme: PresentationTheme, strings: PresentationStrings) -> CGSize {
if let currentParams = self.currentParams, let currentSize = self.currentSize {
if currentParams.constrainedWidth == constrainedWidth &&
currentParams.year == year &&
currentParams.month == month &&
currentParams.theme === theme {
return currentSize
}
}
if self.currentParams?.theme !== theme {
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 27.0, color: theme.rootController.navigationBar.backgroundColor)
}
self.currentParams = (constrainedWidth, year, month, theme)
self.labelNode.attributedText = NSAttributedString(string: stringForMonth(strings: strings, month: month, ofYear: year).uppercased(), font: Font.regular(14.0), textColor: theme.rootController.navigationBar.secondaryTextColor)
let labelSize = self.labelNode.updateLayout(CGSize(width: constrainedWidth, height: .greatestFiniteMagnitude))
let sideInset: CGFloat = 10.0
self.labelNode.frame = CGRect(origin: CGPoint(x: sideInset, y: floor((27.0 - labelSize.height) / 2.0)), size: labelSize)
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: labelSize.width + sideInset * 2.0, height: 27.0))
let size = CGSize(width: labelSize.width + sideInset * 2.0, height: 27.0)
return size
}
}
final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScrollViewDelegate {
private let context: AccountContext
private let peerId: PeerId
private let chatControllerInteraction: ChatControllerInteraction
private let scrollNode: ASScrollNode
private let floatingHeaderNode: FloatingHeaderNode
private var flashHeaderDelayTimer: Foundation.Timer?
private var isDeceleratingAfterTracking = false
private var _itemInteraction: VisualMediaItemInteraction?
private var itemInteraction: VisualMediaItemInteraction {
@ -366,6 +475,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.chatControllerInteraction = chatControllerInteraction
self.scrollNode = ASScrollNode()
self.floatingHeaderNode = FloatingHeaderNode()
self.floatingHeaderNode.alpha = 0.0
super.init()
@ -392,6 +503,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.scrollNode.view.delegate = self
self.addSubnode(self.scrollNode)
self.addSubnode(self.floatingHeaderNode)
self.requestHistoryAroundVisiblePosition()
@ -518,6 +630,12 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
}
}
func cancelPreviewGestures() {
for (_, itemNode) in self.visibleMediaItems {
itemNode.cancelPreviewGesture()
}
}
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
for item in self.mediaItems {
if item.message.id == messageId {
@ -554,7 +672,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
let contentHeight = CGFloat(rowCount + 1) * itemSpacing + CGFloat(rowCount) * itemSize + bottomInset
self.scrollNode.view.contentSize = CGSize(width: size.width, height: contentHeight)
self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: synchronous)
self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, strings: presentationData.strings, synchronousLoad: synchronous)
if isScrollingLockedAtTop {
if self.scrollNode.view.contentOffset.y > .ulpOfOne {
@ -571,11 +689,13 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
for (_, itemNode) in self.visibleMediaItems {
itemNode.cancelPreviewGesture()
}
self.updateHeaderFlashing(animated: true)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let (size, sideInset, bottomInset, visibleHeight, _, presentationData) = self.currentParams {
self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, synchronousLoad: false)
self.updateVisibleItems(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, theme: presentationData.theme, strings: presentationData.strings, synchronousLoad: false)
if scrollView.contentOffset.y >= scrollView.contentSize.height - scrollView.bounds.height * 2.0, let currentView = self.currentView, currentView.earlierId != nil {
if !self.isRequestingView {
@ -586,7 +706,24 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
}
}
private func updateVisibleItems(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, theme: PresentationTheme, synchronousLoad: Bool) {
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if decelerate {
self.isDeceleratingAfterTracking = true
self.updateHeaderFlashing(animated: true)
} else {
self.isDeceleratingAfterTracking = false
self.resetHeaderFlashTimer(start: true)
self.updateHeaderFlashing(animated: true)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.isDeceleratingAfterTracking = false
self.resetHeaderFlashTimer(start: true)
self.updateHeaderFlashing(animated: true)
}
private func updateVisibleItems(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, theme: PresentationTheme, strings: PresentationStrings, synchronousLoad: Bool) {
let availableWidth = size.width - sideInset * 2.0
let itemSpacing: CGFloat = 1.0
@ -595,6 +732,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
let rowCount: Int = self.mediaItems.count / itemsInRow + (self.mediaItems.count % itemsInRow == 0 ? 0 : 1)
let headerItemMinY = self.scrollNode.view.bounds.minY + 20.0
let visibleRect = self.scrollNode.view.bounds.insetBy(dx: 0.0, dy: -400.0)
var minVisibleRow = Int(floor((visibleRect.minY - itemSpacing) / (itemSize + itemSpacing)))
minVisibleRow = max(0, minVisibleRow)
@ -604,6 +742,8 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
let minVisibleIndex = minVisibleRow * itemsInRow
let maxVisibleIndex = min(self.mediaItems.count - 1, (maxVisibleRow + 1) * itemsInRow - 1)
var headerItem: Message?
var validIds = Set<UInt32>()
if minVisibleIndex <= maxVisibleIndex {
for i in minVisibleIndex ... maxVisibleIndex {
@ -622,6 +762,9 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.scrollNode.addSubnode(itemNode)
}
itemNode.frame = itemFrame
if headerItem == nil && itemFrame.maxY > headerItemMinY {
headerItem = self.mediaItems[i].message
}
var itemSynchronousLoad = false
if itemFrame.maxY <= visibleHeight {
itemSynchronousLoad = synchronousLoad
@ -640,6 +783,68 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
itemNode.removeFromSupernode()
}
}
if let headerItem = headerItem {
let (year, month) = listMessageDateHeaderInfo(timestamp: headerItem.timestamp)
let headerSize = self.floatingHeaderNode.update(constrainedWidth: size.width, year: year, month: month, theme: theme, strings: strings)
self.floatingHeaderNode.frame = CGRect(origin: CGPoint(x: floor((size.width - headerSize.width) / 2.0), y: 7.0), size: headerSize)
self.floatingHeaderNode.isHidden = false
} else {
self.floatingHeaderNode.isHidden = true
}
}
private func resetHeaderFlashTimer(start: Bool, duration: Double = 0.3) {
if let flashHeaderDelayTimer = self.flashHeaderDelayTimer {
flashHeaderDelayTimer.invalidate()
self.flashHeaderDelayTimer = nil
}
if start {
final class TimerProxy: NSObject {
private let action: () -> ()
init(_ action: @escaping () -> ()) {
self.action = action
super.init()
}
@objc func timerEvent() {
self.action()
}
}
let timer = Timer(timeInterval: duration, target: TimerProxy { [weak self] in
if let strongSelf = self {
if let flashHeaderDelayTimer = strongSelf.flashHeaderDelayTimer {
flashHeaderDelayTimer.invalidate()
strongSelf.flashHeaderDelayTimer = nil
strongSelf.updateHeaderFlashing(animated: true)
}
}
}, selector: #selector(TimerProxy.timerEvent), userInfo: nil, repeats: false)
self.flashHeaderDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
self.updateHeaderFlashing(animated: true)
}
}
private func headerIsFlashing() -> Bool {
return self.scrollNode.view.isDragging || self.isDeceleratingAfterTracking || self.flashHeaderDelayTimer != nil
}
private func updateHeaderFlashing(animated: Bool) {
let flashing = self.headerIsFlashing()
let alpha: CGFloat = flashing ? 1.0 : 0.0
let previousAlpha = self.floatingHeaderNode.alpha
if !previousAlpha.isEqual(to: alpha) {
self.floatingHeaderNode.alpha = alpha
if animated {
let duration: Double = flashing ? 0.3 : 0.4
self.floatingHeaderNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: duration)
}
}
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

View File

@ -66,6 +66,7 @@ final class PeerInfoScreenData {
let groupsInCommon: GroupsInCommonContext?
let linkedDiscussionPeer: Peer?
let members: PeerInfoMembersData?
let encryptionKeyFingerprint: SecretChatKeyFingerprint?
init(
peer: Peer?,
@ -77,7 +78,8 @@ final class PeerInfoScreenData {
availablePanes: [PeerInfoPaneKey],
groupsInCommon: GroupsInCommonContext?,
linkedDiscussionPeer: Peer?,
members: PeerInfoMembersData?
members: PeerInfoMembersData?,
encryptionKeyFingerprint: SecretChatKeyFingerprint?
) {
self.peer = peer
self.cachedData = cachedData
@ -89,6 +91,7 @@ final class PeerInfoScreenData {
self.groupsInCommon = groupsInCommon
self.linkedDiscussionPeer = linkedDiscussionPeer
self.members = members
self.encryptionKeyFingerprint = encryptionKeyFingerprint
}
}
@ -203,6 +206,8 @@ private func peerInfoScreenInputData(context: AccountContext, peerId: PeerId) ->
}
} else if let group = peer as? TelegramGroup {
return .group(groupId: group.id)
} else if let secretChat = peer as? TelegramSecretChat {
return .user(userId: secretChat.regularPeerId, secretChatId: peer.id, kind: .user)
} else {
return .none
}
@ -272,12 +277,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
availablePanes: [],
groupsInCommon: nil,
linkedDiscussionPeer: nil,
members: nil
members: nil,
encryptionKeyFingerprint: nil
))
case let .user(peerId, secretChatId, kind):
case let .user(userPeerId, secretChatId, kind):
let groupsInCommon: GroupsInCommonContext?
if case .user = kind {
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: peerId)
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: userPeerId)
} else {
groupsInCommon = nil
}
@ -306,9 +312,9 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
subscriber.putNext(data)
}
let disposable = (context.account.viewTracker.peerView(peerId, updateData: false)
let disposable = (context.account.viewTracker.peerView(userPeerId, updateData: false)
|> map { view -> StatusInputData in
guard let user = view.peers[peerId] as? TelegramUser else {
guard let user = view.peers[userPeerId] as? TelegramUser else {
return .none
}
if user.isDeleted {
@ -320,7 +326,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
if user.botInfo != nil {
return .bot
}
guard let presence = view.peerPresences[peerId] as? TelegramUserPresence else {
guard let presence = view.peerPresences[userPeerId] as? TelegramUserPresence else {
return .none
}
return .presence(presence)
@ -366,10 +372,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
var combinedKeys: [PostboxViewKey] = []
combinedKeys.append(globalNotificationsKey)
if let secretChatId = secretChatId {
combinedKeys.append(.peerChatState(peerId: peerId))
combinedKeys.append(.peerChatState(peerId: secretChatId))
}
return combineLatest(
context.account.viewTracker.peerView(peerId, updateData: true),
context.account.viewTracker.peerView(userPeerId, updateData: true),
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
context.account.postbox.combinedView(keys: combinedKeys),
status
@ -382,6 +388,13 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
}
var encryptionKeyFingerprint: SecretChatKeyFingerprint?
if let secretChatId = secretChatId, let peerChatStateView = combinedView.views[.peerChatState(peerId: secretChatId)] as? PeerChatStateView {
if let peerChatState = peerChatStateView.chatState as? SecretChatKeyState {
encryptionKeyFingerprint = peerChatState.keyFingerprint
}
}
var availablePanes = availablePanes
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
if cachedData.commonGroupCount != 0 {
@ -390,7 +403,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
}
return PeerInfoScreenData(
peer: peerView.peers[peerId],
peer: peerView.peers[userPeerId],
cachedData: peerView.cachedData,
status: status,
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
@ -399,7 +412,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
availablePanes: availablePanes ?? [],
groupsInCommon: groupsInCommon,
linkedDiscussionPeer: nil,
members: nil
members: nil,
encryptionKeyFingerprint: encryptionKeyFingerprint
)
}
case .channel:
@ -448,7 +462,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
availablePanes: availablePanes ?? [],
groupsInCommon: nil,
linkedDiscussionPeer: discussionPeer,
members: nil
members: nil,
encryptionKeyFingerprint: nil
)
}
case let .group(groupId):
@ -519,7 +534,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
availablePanes: availablePanes ?? [],
groupsInCommon: nil,
linkedDiscussionPeer: discussionPeer,
members: membersData
members: membersData,
encryptionKeyFingerprint: nil
)
}
}
@ -619,10 +635,12 @@ func availableActionsForMemberOfPeer(accountPeerId: PeerId, peer: Peer, member:
return result
}
func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInfoHeaderButtonKey] {
func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFromChat: Bool) -> [PeerInfoHeaderButtonKey] {
var result: [PeerInfoHeaderButtonKey] = []
if let user = peer as? TelegramUser {
result.append(.message)
if !isOpenedFromChat {
result.append(.message)
}
var callsAvailable = false
if !user.isDeleted, user.botInfo == nil, !user.flags.contains(.isSupport) {
if let cachedUserData = cachedData as? CachedUserData {
@ -634,6 +652,9 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf
result.append(.call)
}
result.append(.mute)
if isOpenedFromChat {
result.append(.search)
}
result.append(.more)
} else if let channel = peer as? TelegramChannel {
switch channel.info {
@ -650,6 +671,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf
}
result.append(.mute)
result.append(.search)
result.append(.more)
} else if let group = peer as? TelegramGroup {
var canEditGroupInfo = false
@ -681,6 +703,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?) -> [PeerInf
}
result.append(.mute)
result.append(.search)
result.append(.more)
}
return result

View File

@ -21,6 +21,7 @@ enum PeerInfoHeaderButtonKey: Hashable {
case mute
case more
case addMember
case search
}
enum PeerInfoHeaderButtonIcon {
@ -30,6 +31,7 @@ enum PeerInfoHeaderButtonIcon {
case unmute
case more
case addMember
case search
}
final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
@ -104,6 +106,8 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
imageName = "Peer Info/ButtonMore"
case .addMember:
imageName = "Peer Info/ButtonAddMember"
case .search:
imageName = "Peer Info/ButtonSearch"
}
if let image = UIImage(bundleImageName: imageName) {
let imageRect = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0)), size: image.size)
@ -273,7 +277,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
})
self.leftHighlightNode.isHidden = true
self.leftHighlightNode.alpha = 0.0
self.rightHighlightNode = ASImageNode()
self.rightHighlightNode.displaysAsynchronously = false
@ -293,7 +297,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
context.drawLinearGradient(gradient, start: CGPoint(x: size.width, y: 0.0), end: CGPoint(x: 0.0, y: 0.0), options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
})
self.rightHighlightNode.isHidden = true
self.rightHighlightNode.alpha = 0.0
self.stripContainerNode = ASDisplayNode()
self.contentNode.addSubnode(self.stripContainerNode)
@ -391,12 +395,26 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
}
if strongSelf.highlightedSide != highlightedSide {
strongSelf.highlightedSide = highlightedSide
let leftAlpha: CGFloat
let rightAlpha: CGFloat
if let highlightedSide = highlightedSide {
strongSelf.leftHighlightNode.isHidden = highlightedSide
strongSelf.rightHighlightNode.isHidden = !highlightedSide
leftAlpha = highlightedSide ? 0.0 : 1.0
rightAlpha = highlightedSide ? 1.0 : 0.0
} else {
strongSelf.leftHighlightNode.isHidden = true
strongSelf.rightHighlightNode.isHidden = true
leftAlpha = 0.0
rightAlpha = 0.0
}
if strongSelf.leftHighlightNode.alpha != leftAlpha {
strongSelf.leftHighlightNode.alpha = leftAlpha
if leftAlpha.isZero {
strongSelf.leftHighlightNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25)
}
}
if strongSelf.rightHighlightNode.alpha != rightAlpha {
strongSelf.rightHighlightNode.alpha = rightAlpha
if rightAlpha.isZero {
strongSelf.rightHighlightNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25)
}
}
}
}
@ -1489,7 +1507,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
private var context: AccountContext
private var presentationData: PresentationData?
private let keepExpandedButtons: PeerInfoScreenKeepExpandedButtons
private let isOpenedFromChat: Bool
private(set) var isAvatarExpanded: Bool
@ -1518,10 +1536,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
var navigationTransition: PeerInfoHeaderNavigationTransition?
init(context: AccountContext, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons) {
init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool) {
self.context = context
self.isAvatarExpanded = avatarInitiallyExpanded
self.keepExpandedButtons = keepExpandedButtons
self.isOpenedFromChat = isOpenedFromChat
self.avatarListNode = PeerInfoAvatarListNode(context: context, readyWhenGalleryLoads: avatarInitiallyExpanded)
@ -1698,7 +1716,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
let buttonKeys: [PeerInfoHeaderButtonKey] = peerInfoHeaderButtons(peer: peer, cachedData: cachedData)
let buttonKeys: [PeerInfoHeaderButtonKey] = peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat)
var isVerified = false
let titleString: NSAttributedString
@ -2077,6 +2095,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
case .addMember:
buttonText = presentationData.strings.PeerInfo_ButtonAddMember
buttonIcon = .addMember
case .search:
buttonText = presentationData.strings.PeerInfo_ButtonSearch
buttonIcon = .search
}
buttonNode.update(size: buttonFrame.size, text: buttonText, icon: buttonIcon, isExpanded: self.isAvatarExpanded, presentationData: presentationData, transition: buttonTransition)
transition.updateSublayerTransformScaleAdditive(node: buttonNode, scale: buttonsScale)
@ -2087,17 +2108,16 @@ final class PeerInfoHeaderNode: ASDisplayNode {
buttonsAlphaTransition.updateAlpha(node: buttonNode, alpha: buttonsAlpha)
let hiddenWhileExpanded: Bool
switch self.keepExpandedButtons {
case .message:
if self.isOpenedFromChat {
switch buttonKey {
case .mute:
case .message, .search:
hiddenWhileExpanded = true
default:
hiddenWhileExpanded = false
}
case .mute:
} else {
switch buttonKey {
case .message:
case .mute, .search:
hiddenWhileExpanded = true
default:
hiddenWhileExpanded = false

View File

@ -16,6 +16,7 @@ protocol PeerInfoPaneNode: ASDisplayNode {
func update(size: CGSize, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, presentationData: PresentationData, synchronous: Bool, transition: ContainedViewLayoutTransition)
func scrollToTop() -> Bool
func transferVelocity(_ velocity: CGFloat)
func cancelPreviewGestures()
func findLoadedMessage(id: MessageId) -> Message?
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
func addToTransitionSurface(view: UIView)
@ -449,7 +450,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
var openPeerContextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?
var requestPerformPeerMemberAction: ((PeerInfoMember, PeerMembersListAction) -> Void)?
var currentPaneUpdated: (() -> Void)?
var currentPaneUpdated: ((Bool) -> Void)?
var requestExpandTabs: (() -> Bool)?
private var currentAvailablePanes: [PeerInfoPaneKey]?
@ -492,6 +493,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
if let (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams {
strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .animated(duration: 0.4, curve: .spring))
strongSelf.currentPaneUpdated?(true)
}
} else if strongSelf.pendingSwitchToPaneKey != key {
strongSelf.pendingSwitchToPaneKey = key
@ -506,11 +509,14 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
override func didLoad() {
super.didLoad()
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), enableBothDirections: true, canBegin: { [weak self] in
guard let strongSelf = self else {
return false
let panRecognizer = InteractiveTransitionGestureRecognizer(target: self, action: #selector(self.panGesture(_:)), allowedDirections: { [weak self] in
guard let strongSelf = self, let currentPaneKey = strongSelf.currentPaneKey, let availablePanes = strongSelf.currentParams?.data?.availablePanes, let index = availablePanes.index(of: currentPaneKey) else {
return []
}
return strongSelf.currentPanes.count > 1
if index == 0 {
return .left
}
return [.left, .right]
})
panRecognizer.delegate = self
panRecognizer.delaysTouchesBegan = false
@ -559,6 +565,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
directionIsToRight = translation.x > size.width / 2.0
}
}
var updated = false
if let directionIsToRight = directionIsToRight {
var updatedIndex = currentIndex
if directionIsToRight {
@ -569,10 +576,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
let switchToKey = availablePanes[updatedIndex]
if switchToKey != self.currentPaneKey && self.currentPanes[switchToKey] != nil{
self.currentPaneKey = switchToKey
updated = true
}
}
self.transitionFraction = 0.0
self.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .animated(duration: 0.35, curve: .spring))
self.currentPaneUpdated?(false)
}
default:
break
@ -853,7 +862,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
}
}
if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey {
self.currentPaneUpdated?()
self.currentPaneUpdated?(true)
}
}
}

View File

@ -493,6 +493,7 @@ private final class PeerInfoInteraction {
let openPeerInfoContextMenu: (PeerInfoContextSubject, ASDisplayNode) -> Void
let performBioLinkAction: (TextLinkItemActionType, TextLinkItem) -> Void
let requestLayout: () -> Void
let openEncryptionKey: () -> Void
init(
openUsername: @escaping (String) -> Void,
@ -521,7 +522,8 @@ private final class PeerInfoInteraction {
performMemberAction: @escaping (PeerInfoMember, PeerInfoMemberAction) -> Void,
openPeerInfoContextMenu: @escaping (PeerInfoContextSubject, ASDisplayNode) -> Void,
performBioLinkAction: @escaping (TextLinkItemActionType, TextLinkItem) -> Void,
requestLayout: @escaping () -> Void
requestLayout: @escaping () -> Void,
openEncryptionKey: @escaping () -> Void
) {
self.openUsername = openUsername
self.openPhone = openPhone
@ -550,6 +552,7 @@ private final class PeerInfoInteraction {
self.openPeerInfoContextMenu = openPeerInfoContextMenu
self.performBioLinkAction = performBioLinkAction
self.requestLayout = requestLayout
self.openEncryptionKey = openEncryptionKey
}
}
@ -642,6 +645,12 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
}
}
if let encryptionKeyFingerprint = data.encryptionKeyFingerprint {
items[.peerInfo]!.append(PeerInfoScreenDisclosureEncryptionKeyItem(id: 6, text: presentationData.strings.Profile_EncryptionKey, fingerprint: encryptionKeyFingerprint, action: {
interaction.openEncryptionKey()
}))
}
if user.botInfo != nil, !user.isVerified {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 5, text: presentationData.strings.ReportPeer_Report, action: {
interaction.openReport(false)
@ -1077,7 +1086,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
private var didSetReady = false
init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons, nearbyPeer: Bool) {
init(controller: PeerInfoScreen, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeer: Bool) {
self.controller = controller
self.context = context
self.peerId = peerId
@ -1087,7 +1096,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
self.scrollNode = ASScrollNode()
self.scrollNode.view.delaysContentTouches = false
self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons)
self.headerNode = PeerInfoHeaderNode(context: context, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat)
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, peerId: peerId)
super.init()
@ -1173,6 +1182,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
},
requestLayout: { [weak self] in
self?.requestLayout()
},
openEncryptionKey: { [weak self] in
self?.openEncryptionKey()
}
)
@ -1556,7 +1568,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
controller.presentInGlobalOverlay(contextController)
}
self.paneContainerNode.currentPaneUpdated = { [weak self] in
self.paneContainerNode.currentPaneUpdated = { [weak self] expand in
guard let strongSelf = self else {
return
}
@ -1573,7 +1585,9 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
strongSelf.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: strongSelf.paneContainerNode.frame.minY - navigationHeight), animated: true)
if expand {
strongSelf.scrollNode.view.setContentOffset(CGPoint(x: 0.0, y: strongSelf.paneContainerNode.frame.minY - navigationHeight), animated: true)
}
}
}
@ -2239,6 +2253,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
controller.present(actionSheet, in: .window(.root))
case .addMember:
self.openAddMember()
case .search:
self.openChatWithMessageSearch()
}
}
@ -2665,6 +2681,13 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, completion: { _ in }), in: .window(.root))
}
private func openEncryptionKey() {
guard let data = self.data, let peer = data.peer, let encryptionKeyFingerprint = data.encryptionKeyFingerprint else {
return
}
self.controller?.push(SecretChatKeyController(context: self.context, fingerprint: encryptionKeyFingerprint, peer: peer))
}
private func openShareBot() {
let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer, _ in
@ -3917,6 +3940,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.canAddVelocity = true
self.canOpenAvatarByDragging = self.headerNode.isAvatarExpanded
self.paneContainerNode.currentPane?.node.cancelPreviewGestures()
}
private var previousVelocityM1: CGFloat = 0.0
@ -4078,16 +4102,11 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
}
public enum PeerInfoScreenKeepExpandedButtons {
case message
case mute
}
public final class PeerInfoScreen: ViewController {
private let context: AccountContext
private let peerId: PeerId
private let avatarInitiallyExpanded: Bool
private let keepExpandedButtons: PeerInfoScreenKeepExpandedButtons
private let isOpenedFromChat: Bool
private let nearbyPeer: Bool
private var presentationData: PresentationData
@ -4104,11 +4123,11 @@ public final class PeerInfoScreen: ViewController {
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
public init(context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool = false, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons = .message, nearbyPeer: Bool = false) {
public init(context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeer: Bool) {
self.context = context
self.peerId = peerId
self.avatarInitiallyExpanded = avatarInitiallyExpanded
self.keepExpandedButtons = keepExpandedButtons
self.isOpenedFromChat = isOpenedFromChat
self.nearbyPeer = nearbyPeer
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -4177,7 +4196,7 @@ public final class PeerInfoScreen: ViewController {
}
override public func loadDisplayNode() {
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, keepExpandedButtons: self.keepExpandedButtons, nearbyPeer: self.nearbyPeer)
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeer: self.nearbyPeer)
self._ready.set(self.controllerNode.ready.get())

View File

@ -29,7 +29,7 @@ private func historyNodeImplForMode(_ mode: PeerMediaCollectionMode, context: Ac
}
return node
case .file:
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .file, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false))
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .file, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false, displayHeaders: .all))
node.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
node.didEndScrolling = { [weak node] in
guard let node = node else {
@ -40,7 +40,7 @@ private func historyNodeImplForMode(_ mode: PeerMediaCollectionMode, context: Ac
node.preloadPages = true
return node
case .music:
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .music, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false))
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .music, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false, displayHeaders: .all))
node.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
node.didEndScrolling = { [weak node] in
guard let node = node else {
@ -51,7 +51,7 @@ private func historyNodeImplForMode(_ mode: PeerMediaCollectionMode, context: Ac
node.preloadPages = true
return node
case .webpage:
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .webPage, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false))
let node = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), tagMask: .webPage, subject: messageId.flatMap { .message($0) }, controllerInteraction: controllerInteraction, selectedMessages: selectedMessages, mode: .list(search: true, reversed: false, displayHeaders: .all))
node.verticalScrollIndicatorColor = theme.list.scrollIndicatorColor
node.didEndScrolling = { [weak node] in
guard let node = node else {

View File

@ -1007,7 +1007,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
public func makePeerInfoController(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, fromChat: Bool) -> ViewController? {
let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: fromChat ? .mute : .message)
let controller = peerInfoControllerImpl(context: context, peer: peer, mode: mode, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: fromChat)
controller?.navigationPresentation = .modalInLargeLayout
return controller
}
@ -1249,19 +1249,20 @@ public final class SharedAccountContextImpl: SharedAccountContext {
private let defaultChatControllerInteraction = ChatControllerInteraction.default
private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, keepExpandedButtons: PeerInfoScreenKeepExpandedButtons) -> ViewController? {
private func peerInfoControllerImpl(context: AccountContext, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool) -> ViewController? {
if let _ = peer as? TelegramGroup {
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons)
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeer: false)
} else if let channel = peer as? TelegramChannel {
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons)
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeer: false)
} else if peer is TelegramUser {
var nearbyPeer = false
if case .nearbyPeer = mode {
nearbyPeer = true
}
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, keepExpandedButtons: keepExpandedButtons, nearbyPeer: nearbyPeer)
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeer: nearbyPeer)
} else if peer is TelegramSecretChat {
return userInfoController(context: context, peerId: peer.id, mode: mode)
//return userInfoController(context: context, peerId: peer.id, mode: mode)
return PeerInfoScreen(context: context, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeer: false)
}
return nil
}

View File

@ -448,12 +448,12 @@ public final class WalletStrings: Equatable {
public var Wallet_SecureStorageReset_Title: String { return self._s[218]! }
public var Wallet_Receive_CommentHeader: String { return self._s[219]! }
public var Wallet_Info_ReceiveGrams: String { return self._s[220]! }
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
}
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
let form = getPluralizationForm(self.lc, value)
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)