mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Peer info bug fixes
This commit is contained in:
parent
9fba3f208a
commit
14e007b236
@ -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";
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
})
|
||||
|
File diff suppressed because it is too large
Load Diff
12
submodules/TelegramUI/Images.xcassets/Peer Info/ButtonSearch.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Peer Info/ButtonSearch.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_search.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/ButtonSearch.imageset/ic_search.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Peer Info/ButtonSearch.imageset/ic_search.pdf
vendored
Normal file
Binary file not shown.
@ -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)
|
||||
|
@ -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 })
|
||||
|
@ -73,7 +73,7 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
|
||||
}
|
||||
|
||||
if presentationInterfaceState.isScheduledMessages {
|
||||
return nil
|
||||
return chatInfoNavigationButton
|
||||
}
|
||||
|
||||
if case .standard(true) = presentationInterfaceState.mode {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -204,6 +204,9 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
}
|
||||
|
||||
func cancelPreviewGestures() {
|
||||
}
|
||||
|
||||
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
return nil
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -247,6 +247,9 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
}
|
||||
|
||||
func cancelPreviewGestures() {
|
||||
}
|
||||
|
||||
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
return nil
|
||||
}
|
||||
|
@ -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? {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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 {
|
||||
|
Binary file not shown.
@ -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
|
||||
}
|
||||
|
Binary file not shown.
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user