mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Calendar
This commit is contained in:
parent
b5d8390a98
commit
03f696fd8f
@ -7032,3 +7032,5 @@ Sorry for the inconvenience.";
|
||||
"Themes.BuildOwn" = "Build Your Own Theme";
|
||||
"Themes.EditCurrentTheme" = "Edit Current Theme";
|
||||
"Themes.CreateNewTheme" = "Create a New Theme";
|
||||
|
||||
"Chat.JumpToDate" = "Jump to Date";
|
||||
|
||||
@ -364,6 +364,11 @@ public struct ChatTextInputStateText: Codable, Equatable {
|
||||
}
|
||||
|
||||
public enum ChatControllerSubject: Equatable {
|
||||
public enum MessageSubject: Equatable {
|
||||
case id(MessageId)
|
||||
case timestamp(Int32)
|
||||
}
|
||||
|
||||
public struct ForwardOptions: Equatable {
|
||||
public let hideNames: Bool
|
||||
public let hideCaptions: Bool
|
||||
@ -374,7 +379,7 @@ public enum ChatControllerSubject: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
case message(id: EngineMessage.Id, highlight: Bool, timecode: Double?)
|
||||
case message(id: MessageSubject, highlight: Bool, timecode: Double?)
|
||||
case scheduledMessages
|
||||
case pinnedMessages(id: EngineMessage.Id?)
|
||||
case forwardedMessages(ids: [EngineMessage.Id], options: Signal<ForwardOptions, NoError>)
|
||||
|
||||
@ -364,6 +364,7 @@ private final class DayComponent: Component {
|
||||
let isEnabled: Bool
|
||||
let theme: PresentationTheme
|
||||
let context: AccountContext
|
||||
let timestamp: Int32
|
||||
let media: DayMedia?
|
||||
let selection: DaySelection
|
||||
let isSelecting: Bool
|
||||
@ -375,6 +376,7 @@ private final class DayComponent: Component {
|
||||
isEnabled: Bool,
|
||||
theme: PresentationTheme,
|
||||
context: AccountContext,
|
||||
timestamp: Int32,
|
||||
media: DayMedia?,
|
||||
selection: DaySelection,
|
||||
isSelecting: Bool,
|
||||
@ -385,6 +387,7 @@ private final class DayComponent: Component {
|
||||
self.isEnabled = isEnabled
|
||||
self.theme = theme
|
||||
self.context = context
|
||||
self.timestamp = timestamp
|
||||
self.media = media
|
||||
self.selection = selection
|
||||
self.isSelecting = isSelecting
|
||||
@ -410,6 +413,9 @@ private final class DayComponent: Component {
|
||||
if lhs.media != rhs.media {
|
||||
return false
|
||||
}
|
||||
if lhs.timestamp != rhs.timestamp {
|
||||
return false
|
||||
}
|
||||
if lhs.selection != rhs.selection {
|
||||
return false
|
||||
}
|
||||
@ -430,6 +436,7 @@ private final class DayComponent: Component {
|
||||
private var action: (() -> Void)?
|
||||
private var currentMedia: DayMedia?
|
||||
|
||||
private(set) var timestamp: Int32?
|
||||
private(set) var index: MessageIndex?
|
||||
private var isHighlightingEnabled: Bool = false
|
||||
|
||||
@ -473,6 +480,7 @@ private final class DayComponent: Component {
|
||||
let isFirstTime = self.action == nil
|
||||
|
||||
self.action = component.action
|
||||
self.timestamp = component.timestamp
|
||||
self.index = component.media?.message.index
|
||||
self.isHighlightingEnabled = component.isEnabled && component.media != nil && !component.isSelecting
|
||||
|
||||
@ -745,6 +753,7 @@ private final class MonthComponent: CombinedComponent {
|
||||
isEnabled: isEnabled,
|
||||
theme: context.component.theme,
|
||||
context: context.component.context,
|
||||
timestamp: dayTimestamp,
|
||||
media: context.component.model.mediaByDay[index],
|
||||
selection: daySelection,
|
||||
isSelecting: context.component.selectedDays != nil,
|
||||
@ -959,8 +968,10 @@ public final class CalendarMessageScreen: ViewController {
|
||||
private let context: AccountContext
|
||||
private let peerId: PeerId
|
||||
private let initialTimestamp: Int32
|
||||
private let navigateToOffset: (Int) -> Void
|
||||
private let previewDay: (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
private let enableMessageRangeDeletion: Bool
|
||||
private let canNavigateToEmptyDays: Bool
|
||||
private let navigateToOffset: (Int, Int32) -> Void
|
||||
private let previewDay: (Int32, MessageIndex?, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var scrollView: Scroller
|
||||
@ -988,11 +999,23 @@ public final class CalendarMessageScreen: ViewController {
|
||||
|
||||
private var ignoreContentOffset: Bool = false
|
||||
|
||||
init(controller: CalendarMessageScreen, context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToOffset: @escaping (Int) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) {
|
||||
init(
|
||||
controller: CalendarMessageScreen,
|
||||
context: AccountContext,
|
||||
peerId: PeerId,
|
||||
calendarSource: SparseMessageCalendar,
|
||||
initialTimestamp: Int32,
|
||||
enableMessageRangeDeletion: Bool,
|
||||
canNavigateToEmptyDays: Bool,
|
||||
navigateToOffset: @escaping (Int, Int32) -> Void,
|
||||
previewDay: @escaping (Int32, MessageIndex?, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.initialTimestamp = initialTimestamp
|
||||
self.enableMessageRangeDeletion = enableMessageRangeDeletion
|
||||
self.canNavigateToEmptyDays = canNavigateToEmptyDays
|
||||
self.calendarSource = calendarSource
|
||||
self.navigateToOffset = navigateToOffset
|
||||
self.previewDay = previewDay
|
||||
@ -1086,8 +1109,11 @@ public final class CalendarMessageScreen: ViewController {
|
||||
currentGestureDayView.isUserInteractionEnabled = false
|
||||
currentGestureDayView.isUserInteractionEnabled = true
|
||||
|
||||
if let index = currentGestureDayView.index {
|
||||
strongSelf.previewDay(index, strongSelf, currentGestureDayView.convert(currentGestureDayView.bounds, to: strongSelf.view), gesture)
|
||||
if currentGestureDayView.index == nil && !strongSelf.canNavigateToEmptyDays {
|
||||
return
|
||||
}
|
||||
if let timestamp = currentGestureDayView.timestamp {
|
||||
strongSelf.previewDay(timestamp, currentGestureDayView.index, strongSelf, currentGestureDayView.convert(currentGestureDayView.bounds, to: strongSelf.view), gesture)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1174,6 +1200,21 @@ public final class CalendarMessageScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func selectDay(timestamp: Int32) {
|
||||
self.selectionState = SelectionState(dayRange: timestamp ... timestamp)
|
||||
|
||||
self.contextGestureContainerNode.isGestureEnabled = self.selectionState == nil
|
||||
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
func openClearHistory(timestamp: Int32) {
|
||||
self.selectionState = SelectionState(dayRange: timestamp ... timestamp)
|
||||
self.selectionToolbarActionSelected()
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let isFirstLayout = self.validLayout == nil
|
||||
self.validLayout = (layout, navigationHeight)
|
||||
@ -1292,8 +1333,8 @@ public final class CalendarMessageScreen: ViewController {
|
||||
let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day)
|
||||
let nextDayTimestamp = dayTimestamp + 24 * 60 * 60
|
||||
|
||||
let minDayTimestamp = dayTimestamp - 24 * 60 * 60
|
||||
let maxDayTimestamp = nextDayTimestamp - 24 * 60 * 60
|
||||
let minDayTimestamp = dayTimestamp
|
||||
let maxDayTimestamp = nextDayTimestamp
|
||||
|
||||
if dayRange.contains(dayTimestamp) {
|
||||
if let currentMinTimestamp = minTimestamp {
|
||||
@ -1401,6 +1442,13 @@ public final class CalendarMessageScreen: ViewController {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.calendarSource.removeMessagesInRange(minTimestamp: minTimestampValue, maxTimestamp: maxTimestampValue, type: type, completion: {
|
||||
Queue.mainQueue().async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.controller?.dismiss(completion: nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1423,18 +1471,6 @@ public final class CalendarMessageScreen: ViewController {
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
beginClear(.forEveryone)
|
||||
|
||||
/*guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.controller?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: confirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
beginClear(.forEveryone)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))*/
|
||||
}))
|
||||
}
|
||||
if let canClearForMyself = info.canClearForMyself {
|
||||
@ -1588,7 +1624,7 @@ public final class CalendarMessageScreen: ViewController {
|
||||
for day in 0 ..< month.numberOfDays {
|
||||
let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day)
|
||||
if dayTimestamp == timestamp {
|
||||
if month.mediaByDay[day] != nil {
|
||||
if month.mediaByDay[day] != nil || strongSelf.canNavigateToEmptyDays {
|
||||
var offset = 0
|
||||
for key in calendarState.messagesByDay.keys.sorted(by: { $0 > $1 }) {
|
||||
if key == dayTimestamp {
|
||||
@ -1597,7 +1633,7 @@ public final class CalendarMessageScreen: ViewController {
|
||||
offset += item.count
|
||||
}
|
||||
}
|
||||
strongSelf.navigateToOffset(offset)
|
||||
strongSelf.navigateToOffset(offset, dayTimestamp)
|
||||
}
|
||||
|
||||
break outer
|
||||
@ -1709,16 +1745,29 @@ public final class CalendarMessageScreen: ViewController {
|
||||
private let peerId: PeerId
|
||||
private let calendarSource: SparseMessageCalendar
|
||||
private let initialTimestamp: Int32
|
||||
private let navigateToDay: (CalendarMessageScreen, Int) -> Void
|
||||
private let previewDay: (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
private let enableMessageRangeDeletion: Bool
|
||||
private let canNavigateToEmptyDays: Bool
|
||||
private let navigateToDay: (CalendarMessageScreen, Int, Int32) -> Void
|
||||
private let previewDay: (Int32, MessageIndex?, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
public init(context: AccountContext, peerId: PeerId, calendarSource: SparseMessageCalendar, initialTimestamp: Int32, navigateToDay: @escaping (CalendarMessageScreen, Int) -> Void, previewDay: @escaping (MessageIndex, ASDisplayNode, CGRect, ContextGesture) -> Void) {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
peerId: PeerId,
|
||||
calendarSource: SparseMessageCalendar,
|
||||
initialTimestamp: Int32,
|
||||
enableMessageRangeDeletion: Bool,
|
||||
canNavigateToEmptyDays: Bool,
|
||||
navigateToDay: @escaping (CalendarMessageScreen, Int, Int32) -> Void,
|
||||
previewDay: @escaping (Int32, MessageIndex?, ASDisplayNode, CGRect, ContextGesture) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.calendarSource = calendarSource
|
||||
self.initialTimestamp = initialTimestamp
|
||||
self.enableMessageRangeDeletion = enableMessageRangeDeletion
|
||||
self.canNavigateToEmptyDays = canNavigateToEmptyDays
|
||||
self.navigateToDay = navigateToDay
|
||||
self.previewDay = previewDay
|
||||
|
||||
@ -1731,9 +1780,11 @@ public final class CalendarMessageScreen: ViewController {
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(dismissPressed)), animated: false)
|
||||
self.navigationItem.setTitle(self.presentationData.strings.MessageCalendar_Title, animated: false)
|
||||
|
||||
/*if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
if self.enableMessageRangeDeletion {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Select, style: .plain, target: self, action: #selector(self.toggleSelectPressed)), animated: false)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
@ -1745,6 +1796,10 @@ public final class CalendarMessageScreen: ViewController {
|
||||
}
|
||||
|
||||
@objc fileprivate func toggleSelectPressed() {
|
||||
if !self.enableMessageRangeDeletion {
|
||||
return
|
||||
}
|
||||
|
||||
self.node.toggleSelectionMode()
|
||||
|
||||
if self.node.selectionState != nil {
|
||||
@ -1754,13 +1809,35 @@ public final class CalendarMessageScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public func selectDay(timestamp: Int32) {
|
||||
self.node.selectDay(timestamp: timestamp)
|
||||
|
||||
if self.node.selectionState != nil {
|
||||
self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.toggleSelectPressed)), animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
public func openClearHistory(timestamp: Int32) {
|
||||
self.node.openClearHistory(timestamp: timestamp)
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = Node(controller: self, context: self.context, peerId: self.peerId, calendarSource: self.calendarSource, initialTimestamp: self.initialTimestamp, navigateToOffset: { [weak self] index in
|
||||
self.displayNode = Node(
|
||||
controller: self,
|
||||
context: self.context,
|
||||
peerId: self.peerId,
|
||||
calendarSource: self.calendarSource,
|
||||
initialTimestamp: self.initialTimestamp,
|
||||
enableMessageRangeDeletion: self.enableMessageRangeDeletion,
|
||||
canNavigateToEmptyDays: self.canNavigateToEmptyDays,
|
||||
navigateToOffset: { [weak self] index, timestamp in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.navigateToDay(strongSelf, index)
|
||||
}, previewDay: self.previewDay)
|
||||
strongSelf.navigateToDay(strongSelf, index, timestamp)
|
||||
},
|
||||
previewDay: self.previewDay
|
||||
)
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
@ -691,7 +691,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass {
|
||||
scrollToEndIfExists = true
|
||||
}
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(id: messageId, highlight: true, timecode: nil), purposefulAction: {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), purposefulAction: {
|
||||
if deactivateOnAction {
|
||||
self?.deactivateSearch(animated: false)
|
||||
}
|
||||
@ -861,7 +861,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
} else {
|
||||
var subject: ChatControllerSubject?
|
||||
if case let .search(messageId) = source, let id = messageId {
|
||||
subject = .message(id: id, highlight: false, timecode: nil)
|
||||
subject = .message(id: .id(id), highlight: false, timecode: nil)
|
||||
}
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.id), subject: subject, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
|
||||
@ -56,7 +56,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
if let strongSelf = self {
|
||||
strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer._asPeer()) |> deliverOnMainQueue).start(next: { actualPeerId in
|
||||
if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: message.id, highlight: true, timecode: nil) : nil, keepStack: .always))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: .id(message.id), highlight: true, timecode: nil) : nil, keepStack: .always))
|
||||
}
|
||||
}))
|
||||
strongSelf.controllerNode.listNode.clearHighlightAnimated(true)
|
||||
|
||||
@ -1119,7 +1119,7 @@ public final class SparseItemGrid: ASDisplayNode {
|
||||
let previousProgress = self.currentProgress
|
||||
self.currentProgress = progress
|
||||
|
||||
let fixedAnchorPoint = CGPoint(x: fromAnchorFrame.minX + 1.0, y: fromAnchorFrame.minY + 1.0)
|
||||
let fixedAnchorPoint = CGPoint(x: toAnchorFrame.midX, y: toAnchorFrame.midY)
|
||||
|
||||
if let fromItem = self.fromViewport.anchorItem(at: fixedAnchorPoint), let fromFrame = self.fromViewport.frameForItem(at: fromItem.index) {
|
||||
fromAnchorFrame.origin.y = fromFrame.midY
|
||||
|
||||
@ -518,7 +518,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in
|
||||
c.dismiss(completion: {
|
||||
if let navigationController = controller?.navigationController as? NavigationController {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: nil)))
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil)))
|
||||
}
|
||||
})
|
||||
})))
|
||||
|
||||
@ -263,7 +263,7 @@ public func messageStatsController(context: AccountContext, messageId: MessageId
|
||||
}
|
||||
navigateToMessageImpl = { [weak controller] messageId in
|
||||
if let navigationController = controller?.navigationController as? NavigationController {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil))
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil))
|
||||
}
|
||||
}
|
||||
return controller
|
||||
|
||||
@ -758,7 +758,7 @@ final class AuthorizedApplicationContext {
|
||||
}
|
||||
|
||||
let navigateToMessage = {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil)))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil)))
|
||||
}
|
||||
|
||||
if chatIsVisible {
|
||||
@ -837,7 +837,7 @@ final class AuthorizedApplicationContext {
|
||||
|
||||
if visiblePeerId != peerId || messageId != nil {
|
||||
if self.rootController.rootTabController != nil {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) }, activateInput: activateInput))
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) }, activateInput: activateInput))
|
||||
} else {
|
||||
self.scheduledOpenChatWithPeerId = (peerId, messageId, activateInput)
|
||||
}
|
||||
|
||||
@ -63,6 +63,7 @@ import Speak
|
||||
import UniversalMediaPlayer
|
||||
import WallpaperBackgroundNode
|
||||
import ChatListUI
|
||||
import CalendarMessageScreen
|
||||
|
||||
#if DEBUG
|
||||
import os.signpost
|
||||
@ -2100,13 +2101,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { [weak self] timestamp in
|
||||
}, navigateToFirstDateMessage: { [weak self] timestamp, alreadyThere in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerId):
|
||||
if alreadyThere {
|
||||
strongSelf.openCalendarSearch(timestamp: timestamp)
|
||||
} else {
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
|
||||
}
|
||||
case let .replyThread(replyThreadMessage):
|
||||
let peerId = replyThreadMessage.messageId.peerId
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
|
||||
@ -5006,7 +5011,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
self.chatDisplayNode.historyNode.scrolledToIndex = { [weak self] toIndex, initial in
|
||||
if let strongSelf = self, case let .message(index) = toIndex {
|
||||
if case let .message(messageId, _, _) = strongSelf.subject, initial, messageId != index.id {
|
||||
if case let .message(messageSubject, _, _) = strongSelf.subject, initial, case let .id(messageId) = messageSubject, messageId != index.id {
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(text: strongSelf.presentationData.strings.Conversation_MessageDoesntExist), elevatedLayout: false, action: { _ in return true }), in: .current)
|
||||
} else if let controllerInteraction = strongSelf.controllerInteraction {
|
||||
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(index.id) {
|
||||
@ -6076,37 +6081,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
}, openCalendarSearch: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
|
||||
let controller = ChatDateSelectionSheet(presentationData: strongSelf.presentationData, completion: { timestamp in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.messageId.peerId
|
||||
threadId = makeMessageThreadId(replyThreadMessage.messageId)
|
||||
}
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).start(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
if let messageId = messageId {
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil), forceInCurrentChat: true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}
|
||||
self?.openCalendarSearch(timestamp: Int32(Date().timeIntervalSince1970))
|
||||
}, toggleMembersSearch: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||
@ -7288,7 +7263,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
if let navigationController = strongSelf.effectiveNavigationController {
|
||||
let subject: ChatControllerSubject? = sourceMessageId.flatMap { ChatControllerSubject.message(id: $0, highlight: true, timecode: nil) }
|
||||
let subject: ChatControllerSubject? = sourceMessageId.flatMap { ChatControllerSubject.message(id: .id($0), highlight: true, timecode: nil) }
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadResult), subject: subject, keepStack: .always))
|
||||
}
|
||||
}, activatePinnedListPreview: { [weak self] node, gesture in
|
||||
@ -11309,6 +11284,127 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
|
||||
private func openCalendarSearch(timestamp: Int32) {
|
||||
guard case let .peer(peerId) = self.chatLocation else {
|
||||
return
|
||||
}
|
||||
self.chatDisplayNode.dismissInput()
|
||||
|
||||
let initialTimestamp = timestamp
|
||||
var dismissCalendarScreen: (() -> Void)?
|
||||
var selectDay: ((Int32) -> Void)?
|
||||
var openClearHistory: ((Int32) -> Void)?
|
||||
|
||||
let calendarScreen = CalendarMessageScreen(
|
||||
context: self.context,
|
||||
peerId: peerId,
|
||||
calendarSource: self.context.engine.messages.sparseMessageCalendar(peerId: peerId, tag: .photoOrVideo),
|
||||
initialTimestamp: initialTimestamp,
|
||||
enableMessageRangeDeletion: true,
|
||||
canNavigateToEmptyDays: true,
|
||||
navigateToDay: { [weak self] c, index, timestamp in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
c.dismiss()
|
||||
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.messageId.peerId
|
||||
threadId = makeMessageThreadId(replyThreadMessage.messageId)
|
||||
}
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).start(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
if let messageId = messageId {
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil), forceInCurrentChat: true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
},
|
||||
previewDay: { [weak self] timestamp, _, sourceNode, sourceRect, gesture in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Chat_JumpToDate, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
dismissCalendarScreen?()
|
||||
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.messageId.peerId
|
||||
threadId = makeMessageThreadId(replyThreadMessage.messageId)
|
||||
}
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).start(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
if let messageId = messageId {
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, nil), forceInCurrentChat: true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
})))
|
||||
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.DialogList_ClearHistoryConfirmation, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
openClearHistory?(timestamp)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Common_Select, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
selectDay?(timestamp)
|
||||
})))
|
||||
}
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: .timestamp(timestamp), highlight: false, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(items: items)), gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
)
|
||||
|
||||
self.push(calendarScreen)
|
||||
dismissCalendarScreen = { [weak calendarScreen] in
|
||||
calendarScreen?.dismiss(completion: nil)
|
||||
}
|
||||
selectDay = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.selectDay(timestamp: timestamp)
|
||||
}
|
||||
openClearHistory = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.openClearHistory(timestamp: timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
private func openMessageReplies(messageId: MessageId, displayProgressInMessage: MessageId?, isChannelPost: Bool, atMessage atMessageId: MessageId?, displayModalProgress: Bool) {
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
@ -11382,9 +11478,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let subject: ChatControllerSubject?
|
||||
if let atMessageId = atMessageId {
|
||||
subject = .message(id: atMessageId, highlight: true, timecode: nil)
|
||||
subject = .message(id: .id(atMessageId), highlight: true, timecode: nil)
|
||||
} else if let index = result.scrollToLowerBoundMessage {
|
||||
subject = .message(id: index.id, highlight: false, timecode: nil)
|
||||
subject = .message(id: .id(index.id), highlight: false, timecode: nil)
|
||||
} else {
|
||||
subject = nil
|
||||
}
|
||||
@ -11447,11 +11543,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if isPinnedMessages, let messageId = messageLocation.messageId {
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.dismiss()
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always))
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), keepStack: .always))
|
||||
}
|
||||
} else if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, (messageId.peerId != peerId && !forceInCurrentChat) || (isScheduledMessages && messageId.id != 0 && !Namespaces.Message.allScheduled.contains(messageId.namespace)) {
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true, timecode: nil), keepStack: .always))
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: .id(messageId), highlight: true, timecode: nil), keepStack: .always))
|
||||
}
|
||||
} else if forceInCurrentChat {
|
||||
if let _ = fromId, let fromIndex = fromIndex, rememberInStack {
|
||||
@ -11613,7 +11709,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
completion?()
|
||||
} else {
|
||||
if let navigationController = strongSelf.effectiveNavigationController {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) }))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) }))
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
@ -11625,7 +11721,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
} else {
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true, timecode: nil) }))
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) }))
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
@ -12399,9 +12495,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
switch navigation {
|
||||
case let .chat(_, subject, peekData):
|
||||
if case .peer(peerId) = strongSelf.chatLocation {
|
||||
if let subject = subject, case let .message(messageId, _, timecode) = subject {
|
||||
if let subject = subject, case let .message(messageSubject, _, timecode) = subject {
|
||||
if case let .id(messageId) = messageSubject {
|
||||
strongSelf.navigateToMessage(from: sourceMessageId, to: .id(messageId, timecode))
|
||||
}
|
||||
}
|
||||
} else if let navigationController = strongSelf.effectiveNavigationController {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: subject, keepStack: .always, peekData: peekData))
|
||||
}
|
||||
@ -13604,22 +13702,25 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
weak var sourceNode: ASDisplayNode?
|
||||
let sourceRect: CGRect?
|
||||
|
||||
let navigationController: NavigationController? = nil
|
||||
|
||||
let passthroughTouches: Bool
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?, passthroughTouches: Bool) {
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?, sourceRect: CGRect? = nil, passthroughTouches: Bool) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
self.sourceRect = sourceRect
|
||||
self.passthroughTouches = passthroughTouches
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||
let sourceNode = self.sourceNode
|
||||
let sourceRect = self.sourceRect
|
||||
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||
if let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds)
|
||||
return (sourceNode, sourceRect ?? sourceNode.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ public final class ChatControllerInteraction {
|
||||
let openSearch: () -> Void
|
||||
let setupReply: (MessageId) -> Void
|
||||
let canSetupReply: (Message) -> ChatControllerInteractionSwipeAction
|
||||
let navigateToFirstDateMessage: (Int32) -> Void
|
||||
let navigateToFirstDateMessage: (Int32, Bool) -> Void
|
||||
let requestRedeliveryOfFailedMessages: (MessageId) -> Void
|
||||
let addContact: (String) -> Void
|
||||
let rateCall: (Message, CallId, Bool) -> Void
|
||||
@ -181,7 +181,7 @@ public final class ChatControllerInteraction {
|
||||
openSearch: @escaping () -> Void,
|
||||
setupReply: @escaping (MessageId) -> Void,
|
||||
canSetupReply: @escaping (Message) -> ChatControllerInteractionSwipeAction,
|
||||
navigateToFirstDateMessage: @escaping(Int32) ->Void,
|
||||
navigateToFirstDateMessage: @escaping(Int32, Bool) ->Void,
|
||||
requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void,
|
||||
addContact: @escaping (String) -> Void,
|
||||
rateCall: @escaping (Message, CallId, Bool) -> Void,
|
||||
@ -315,7 +315,7 @@ public final class ChatControllerInteraction {
|
||||
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
|
||||
@ -951,8 +951,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(anchorIndex), anchorIndex: .message(anchorIndex), count: historyMessageCount, highlight: false), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
}
|
||||
} else {
|
||||
if let subject = subject, case let .message(messageId, highlight, _) = subject {
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
if let subject = subject, case let .message(messageSubject, highlight, _) = subject {
|
||||
let initialSearchLocation: ChatHistoryInitialSearchLocation
|
||||
switch messageSubject {
|
||||
case let .id(id):
|
||||
initialSearchLocation = .id(id)
|
||||
case let .timestamp(timestamp):
|
||||
initialSearchLocation = .index(MessageIndex(id: MessageId(peerId: strongSelf.chatLocation.peerId, namespace: Namespaces.Message.Cloud, id: 1), timestamp: timestamp))
|
||||
}
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: initialSearchLocation, count: 60, highlight: highlight), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
} else if let subject = subject, case let .pinnedMessages(maybeMessageId) = subject, let messageId = maybeMessageId {
|
||||
strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: true), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0)
|
||||
} else if var chatHistoryLocation = strongSelf.chatHistoryLocationValue {
|
||||
@ -1207,8 +1214,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
}
|
||||
})
|
||||
|
||||
if let subject = subject, case let .message(messageId, highlight, _) = subject {
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: 0)
|
||||
if let subject = subject, case let .message(messageSubject, highlight, _) = subject {
|
||||
let initialSearchLocation: ChatHistoryInitialSearchLocation
|
||||
switch messageSubject {
|
||||
case let .id(id):
|
||||
initialSearchLocation = .id(id)
|
||||
case let .timestamp(timestamp):
|
||||
initialSearchLocation = .index(MessageIndex(id: MessageId(peerId: self.chatLocation.peerId, namespace: Namespaces.Message.Cloud, id: 1), timestamp: timestamp))
|
||||
}
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: initialSearchLocation, count: 60, highlight: highlight), id: 0)
|
||||
} else if let subject = subject, case let .pinnedMessages(maybeMessageId) = subject, let messageId = maybeMessageId {
|
||||
self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: true), id: 0)
|
||||
} else {
|
||||
|
||||
@ -1520,7 +1520,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil)
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: .id(attribute.messageId), highlight: true, timecode: nil), peekData: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2849,7 +2849,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil)
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: .id(attribute.messageId), highlight: true, timecode: nil), peekData: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,9 +26,9 @@ final class ChatMessageDateHeader: ListViewItemHeader {
|
||||
let id: ListViewItemNode.HeaderId
|
||||
let presentationData: ChatPresentationData
|
||||
let context: AccountContext
|
||||
let action: ((Int32) -> Void)?
|
||||
let action: ((Int32, Bool) -> Void)?
|
||||
|
||||
init(timestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
init(timestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) {
|
||||
self.timestamp = timestamp
|
||||
self.scheduled = scheduled
|
||||
self.presentationData = presentationData
|
||||
@ -117,9 +117,9 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
|
||||
private var flashingOnScrolling = false
|
||||
private var stickDistanceFactor: CGFloat = 0.0
|
||||
private var action: ((Int32) -> Void)? = nil
|
||||
private var action: ((Int32, Bool) -> Void)? = nil
|
||||
|
||||
init(localTimestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32) -> Void)? = nil) {
|
||||
init(localTimestamp: Int32, scheduled: Bool, presentationData: ChatPresentationData, context: AccountContext, action: ((Int32, Bool) -> Void)? = nil) {
|
||||
self.presentationData = presentationData
|
||||
self.context = context
|
||||
|
||||
@ -309,7 +309,7 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
|
||||
|
||||
@objc func tapGesture(_ recognizer: ListViewTapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.action?(self.localTimestamp)
|
||||
self.action?(self.localTimestamp, self.stickDistanceFactor < 0.5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -827,7 +827,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil)
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: .id(attribute.messageId), highlight: true, timecode: nil), peekData: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -328,14 +328,14 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
isScheduledMessages = true
|
||||
}
|
||||
|
||||
self.dateHeader = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp in
|
||||
self.dateHeader = ChatMessageDateHeader(timestamp: content.index.timestamp, scheduled: isScheduledMessages, presentationData: presentationData, context: context, action: { timestamp, alreadyThere in
|
||||
var calendar = NSCalendar.current
|
||||
calendar.timeZone = TimeZone(abbreviation: "UTC")!
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp))
|
||||
let components = calendar.dateComponents([.year, .month, .day], from: date)
|
||||
|
||||
if let date = calendar.date(from: components) {
|
||||
controllerInteraction.navigateToFirstDateMessage(Int32(date.timeIntervalSince1970))
|
||||
controllerInteraction.navigateToFirstDateMessage(Int32(date.timeIntervalSince1970), alreadyThere)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@ -975,7 +975,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||
openPeerId = attribute.messageId.peerId
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true, timecode: nil), peekData: nil)
|
||||
navigate = .chat(textInputState: nil, subject: .message(id: .id(attribute.messageId), highlight: true, timecode: nil), peekData: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -70,7 +70,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
} else {
|
||||
var subject: ChatControllerSubject?
|
||||
if let messageId = adAttribute.messageId {
|
||||
subject = .message(id: messageId, highlight: true, timecode: nil)
|
||||
subject = .message(id: .id(messageId), highlight: true, timecode: nil)
|
||||
}
|
||||
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
|
||||
}
|
||||
|
||||
@ -489,7 +489,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
@ -884,11 +884,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
break
|
||||
case let .channelMessage(peerId, messageId, timecode):
|
||||
if let navigationController = strongSelf.getNavigationController() {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: timecode)))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: .id(messageId), highlight: true, timecode: timecode)))
|
||||
}
|
||||
case let .replyThreadMessage(replyThreadMessage, messageId):
|
||||
if let navigationController = strongSelf.getNavigationController() {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(id: messageId, highlight: true, timecode: nil)))
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(id: .id(messageId), highlight: true, timecode: nil)))
|
||||
}
|
||||
case let .stickerPack(name):
|
||||
let packReference: StickerPackReference = .name(name)
|
||||
|
||||
@ -232,7 +232,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
switch item.content {
|
||||
case let .peer(messages, peer, _, _, _, _, _, _, _, _, _, _):
|
||||
if let message = messages.first {
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: .message(id: message.id, highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(items: [])), gesture: gesture)
|
||||
presentInGlobalOverlay(contextController)
|
||||
|
||||
@ -118,7 +118,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
|
||||
@ -20,7 +20,8 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
if let updateTextInputState = params.updateTextInputState {
|
||||
controller.updateTextInputState(updateTextInputState)
|
||||
}
|
||||
if let subject = params.subject, case let .message(messageId, _, timecode) = subject {
|
||||
if let subject = params.subject, case let .message(messageSubject, _, timecode) = subject {
|
||||
if case let .id(messageId) = messageSubject {
|
||||
let navigationController = params.navigationController
|
||||
let animated = params.animated
|
||||
controller.navigateToMessage(messageLocation: .id(messageId, timecode), animated: isFirst, completion: { [weak navigationController, weak controller] in
|
||||
@ -30,6 +31,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
}, customPresentProgress: { [weak navigationController] c, a in
|
||||
(navigationController?.viewControllers.last as? ViewController)?.present(c, in: .window(.root), with: a)
|
||||
})
|
||||
}
|
||||
} else if params.scrollToEndIfExists && isFirst {
|
||||
controller.scrollToEndOfHistory()
|
||||
let _ = params.navigationController.popToViewController(controller, animated: params.animated)
|
||||
|
||||
@ -103,7 +103,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
||||
dismissInput()
|
||||
navigationController?.pushViewController(controller)
|
||||
case let .channelMessage(peerId, messageId, timecode):
|
||||
openPeer(peerId, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true, timecode: timecode), peekData: nil))
|
||||
openPeer(peerId, .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: true, timecode: timecode), peekData: nil))
|
||||
case let .replyThreadMessage(replyThreadMessage, messageId):
|
||||
if let navigationController = navigationController {
|
||||
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in
|
||||
|
||||
@ -110,7 +110,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
@ -186,7 +186,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
self.isGlobalSearch = false
|
||||
}
|
||||
|
||||
self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: initialMessageId, highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch))
|
||||
self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch))
|
||||
self.historyNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
@ -528,7 +528,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
}
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: messageId, highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch))
|
||||
let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch))
|
||||
historyNode.clipsToBounds = true
|
||||
historyNode.preloadPages = true
|
||||
historyNode.stackFromBottom = true
|
||||
|
||||
@ -1800,7 +1800,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
c.dismiss(completion: {
|
||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
let currentPeerId = strongSelf.peerId
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
var indexesToRemove = Set<Int>()
|
||||
var keptCurrentChatController = false
|
||||
@ -1946,7 +1946,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
c.dismiss(completion: {
|
||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
let currentPeerId = strongSelf.peerId
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: message.id, highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {
|
||||
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(currentPeerId), subject: .message(id: .id(message.id), highlight: true, timecode: nil), keepStack: .always, useExisting: false, purposefulAction: {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
var indexesToRemove = Set<Int>()
|
||||
var keptCurrentChatController = false
|
||||
@ -2198,7 +2198,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
@ -6249,7 +6249,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
var dismissCalendarScreen: (() -> Void)?
|
||||
|
||||
let calendarScreen = CalendarMessageScreen(context: self.context, peerId: self.peerId, calendarSource: calendarSource, initialTimestamp: initialTimestamp, navigateToDay: { [weak self] c, index in
|
||||
let calendarScreen = CalendarMessageScreen(
|
||||
context: self.context,
|
||||
peerId: self.peerId,
|
||||
calendarSource: calendarSource,
|
||||
initialTimestamp: initialTimestamp,
|
||||
enableMessageRangeDeletion: false,
|
||||
canNavigateToEmptyDays: false,
|
||||
navigateToDay: { [weak self] c, index, _ in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss()
|
||||
return
|
||||
@ -6262,8 +6269,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
pane.scrollToItem(index: index)
|
||||
|
||||
c.dismiss()
|
||||
}, previewDay: { [weak self] index, sourceNode, sourceRect, gesture in
|
||||
guard let strongSelf = self else {
|
||||
},
|
||||
previewDay: { [weak self] _, index, sourceNode, sourceRect, gesture in
|
||||
guard let strongSelf = self, let index = index else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -6284,7 +6292,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
chatController: nil,
|
||||
context: strongSelf.context,
|
||||
chatLocation: .peer(strongSelf.peerId),
|
||||
subject: .message(id: index.id, highlight: false, timecode: nil),
|
||||
subject: .message(id: .id(index.id), highlight: false, timecode: nil),
|
||||
botStart: nil,
|
||||
updateTextInputState: nil,
|
||||
activateInput: false,
|
||||
@ -6306,11 +6314,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
))
|
||||
})))
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(id: index.id, highlight: false, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(id: .id(index.id), highlight: false, timecode: nil), botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(items: items)), gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
self.controller?.push(calendarScreen)
|
||||
dismissCalendarScreen = { [weak calendarScreen] in
|
||||
|
||||
@ -1255,7 +1255,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
}, presentGlobalOverlayController: { _, _ in }, callPeer: { _, _ in }, longTap: { _, _ in }, openCheckoutOrReceipt: { _ in }, openSearch: { }, setupReply: { _ in
|
||||
}, canSetupReply: { _ in
|
||||
return .none
|
||||
}, navigateToFirstDateMessage: { _ in
|
||||
}, navigateToFirstDateMessage: { _, _ in
|
||||
}, requestRedeliveryOfFailedMessages: { _ in
|
||||
}, addContact: { _ in
|
||||
}, rateCall: { _, _, _ in
|
||||
|
||||
@ -59,7 +59,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
|
||||
openResolvedPeerImpl(peerId, navigation)
|
||||
case let .channelMessage(peerId, messageId, timecode):
|
||||
if let navigationController = controller.navigationController as? NavigationController {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true, timecode: timecode)))
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: .id(messageId), highlight: true, timecode: timecode)))
|
||||
}
|
||||
case let .replyThreadMessage(replyThreadMessage, messageId):
|
||||
if let navigationController = controller.navigationController as? NavigationController {
|
||||
|
||||
@ -425,7 +425,7 @@ private func resolveInternalUrl(context: AccountContext, url: ParsedInternalUrl)
|
||||
return .replyThreadMessage(replyThreadMessage: result, messageId: messageId)
|
||||
}
|
||||
} else {
|
||||
return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true, timecode: timecode), peekData: nil)))
|
||||
return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(id: .id(messageId), highlight: true, timecode: timecode), peekData: nil)))
|
||||
}
|
||||
} else {
|
||||
return .single(.inaccessiblePeer)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user